From 98dc756161108b5d01280c54d7b475ab4dd59489 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 21 Oct 2015 14:36:07 -0500 Subject: [PATCH 001/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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/476] 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 ecf77d43f4be0276f321bc924c7516afdb31f2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 6 Sep 2019 01:44:43 +0200 Subject: [PATCH 081/476] Tag docker images with their commit SHA so we can point to them from binder's Dockerfile. Note that mybinder does not support moving targets such as branches. --- .ci/build-docker.sh | 3 +++ .ci/update-env.sh | 2 ++ .gitlab-ci.yml | 1 + 3 files changed, 6 insertions(+) diff --git a/.ci/build-docker.sh b/.ci/build-docker.sh index 56c837b8322..05ce598cb6c 100755 --- a/.ci/build-docker.sh +++ b/.ci/build-docker.sh @@ -41,6 +41,9 @@ docker_build --target make-all --tag make-all:$DOCKER_TAG . # Build the release image without build artifacts. docker_build --target sagemath --tag "$DOCKER_IMAGE_CLI" . +# Tag the sagemath:$DOCKER_TAG image that CI has just built as +# sagemath:$COMMIT_HASH so we can refer to it uniquely later. +docker tag "$DOCKER_IMAGE_CLI" "$DOCKER_IMAGE_BINDER" # Display the layers of this image docker history "$DOCKER_IMAGE_CLI" # Build the developer image with the build artifacts intact. diff --git a/.ci/update-env.sh b/.ci/update-env.sh index 77e1cca4152..60544b4dbda 100755 --- a/.ci/update-env.sh +++ b/.ci/update-env.sh @@ -45,6 +45,8 @@ fi export DOCKER_IMAGE_CLI=${DOCKER_NAMESPACE:-sagemath}/sagemath:$DOCKER_TAG export DOCKER_IMAGE_DEV=${DOCKER_NAMESPACE:-sagemath}/sagemath-dev:$DOCKER_TAG +export DOCKER_IMAGE_BINDER="${DOCKER_NAMESPACE:-sagemath}/sagemath:${CI_COMMIT_SHA}}" + # Seed the build cache with this image (set to source-clean to build from # scratch.) export ARTIFACT_BASE=${ARTIFACT_BASE:-$DEFAULT_ARTIFACT_BASE} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e2f2427b02e..f43501e216c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -99,6 +99,7 @@ build-from-latest: - .ci/build-docker.sh | tee gitlab-build-docker.log | .ci/head-tail.sh 1048576 - .ci/push-gitlab.sh sagemath-dev - .ci/push-gitlab.sh sagemath + - DOCKER_TAG=$CI_COMMIT_SHA .ci/push-gitlab.sh sagemath except: - master - develop From e353fd549e71e3d97656942373ab1e8e3d770898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 6 Sep 2019 03:30:40 +0200 Subject: [PATCH 082/476] fix typo --- .ci/update-env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/update-env.sh b/.ci/update-env.sh index 60544b4dbda..60ace995da1 100755 --- a/.ci/update-env.sh +++ b/.ci/update-env.sh @@ -45,7 +45,7 @@ fi export DOCKER_IMAGE_CLI=${DOCKER_NAMESPACE:-sagemath}/sagemath:$DOCKER_TAG export DOCKER_IMAGE_DEV=${DOCKER_NAMESPACE:-sagemath}/sagemath-dev:$DOCKER_TAG -export DOCKER_IMAGE_BINDER="${DOCKER_NAMESPACE:-sagemath}/sagemath:${CI_COMMIT_SHA}}" +export DOCKER_IMAGE_BINDER="${DOCKER_NAMESPACE:-sagemath}/sagemath:${CI_COMMIT_SHA}" # Seed the build cache with this image (set to source-clean to build from # scratch.) From 002ae1523d5144769aba55a1a158ea04e999dc6a Mon Sep 17 00:00:00 2001 From: Bryan Gillespie Date: Sat, 4 Apr 2020 12:13:16 -0600 Subject: [PATCH 083/476] 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 084/476] 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 085/476] 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 086/476] 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 087/476] 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 088/476] 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 089/476] 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 090/476] 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 091/476] 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 092/476] 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 093/476] 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 71c02c0e0834f7119b528ff884c584b44308076c Mon Sep 17 00:00:00 2001 From: rbmj Date: Fri, 17 Apr 2020 13:57:02 -0400 Subject: [PATCH 094/476] Add logarithmic point selection to generate_plot_points() In plot(), if scale == 'semilogx' or 'loglog' when calling plot, it will now call the modified mode of generate_plot_points() that will select the points to evaluate exponentially. This places the evaluated points evenly along the viewport's x axis which decreases the number of points that are needed for accurate log-scale plots. --- src/sage/plot/plot.py | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 1000ef2380a..df1528f8632 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -589,7 +589,8 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 from sage.arith.srange import srange from sage.misc.randstate import current_randstate #for plot adaptive refinement -from math import sin, cos, pi #for polar_plot +from math import sin, cos, pi, log, exp #for polar_plot and log scaling + from sage.ext.fast_eval import fast_float, is_fast_float @@ -1946,8 +1947,12 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) raise ValueError('only one of color or rgbcolor should be specified') elif 'color' in kwds: kwds['rgbcolor'] = kwds.pop('color', (0,0,1)) # take blue as default ``rgbcolor`` + G_kwds = Graphics._extract_kwds_for_show(kwds, ignore=['xmin', 'xmax']) + if 'scale' in G_kwds: + kwds['scale'] = G_kwds['scale'] # pass down so plot knows if log-scale + original_opts = kwds.pop('__original_opts', {}) do_show = kwds.pop('show',False) @@ -2103,6 +2108,12 @@ def _plot(funcs, xrange, parametric=False, else: f = funcs + #check to see if this is a log scale graph on the x axis + exp_points = False + if ('scale' in options.keys() and not parametric and + (options['scale'] == 'loglog' or options['scale'] == 'semilogx')): + exp_points = True + # Keep ``rgbcolor`` option 'automatic' only for lists of functions. # Otherwise, let the plot color be 'blue'. if parametric or not isinstance(funcs, (list, tuple)): @@ -2277,11 +2288,11 @@ def golden_rainbow(i,lightness=0.4): for x in excluded_points], []) data = generate_plot_points(f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, - randomize, initial_points) + randomize, initial_points, exp_dist=exp_points) else: data = generate_plot_points(f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, - randomize) + randomize, exp_dist=exp_points) for i in range(len(data)-1): @@ -2334,7 +2345,7 @@ def golden_rainbow(i,lightness=0.4): fill_f = fill filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, \ - adaptive_recursion, randomize) + adaptive_recursion, randomize, exp_dist=exp_points) filldata.reverse() filldata += data else: @@ -2345,7 +2356,7 @@ def golden_rainbow(i,lightness=0.4): if not hasattr(fill, '__call__') and polar: filldata = generate_plot_points(lambda x: base_level, xrange, plot_points, adaptive_tolerance, \ - adaptive_recursion, randomize) + adaptive_recursion, randomize, exp_dist=exp_points) filldata.reverse() filldata += data if not hasattr(fill, '__call__') and not polar: @@ -3794,7 +3805,7 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=5 return [] -def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize=True, initial_points=None): +def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize=True, initial_points=None, exp_dist=False): r""" Calculate plot points for a function f in the interval xrange. The adaptive refinement algorithm is also automatically invoked with a @@ -3822,6 +3833,9 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap - ``initial_points`` - (default: None) a list of points that should be evaluated. + - ``exp_dist`` - (default: False) whether points should be distributed linearly + (False) or exponentially (True) within the range specified + OUTPUT: - a list of points (x, f(x)) in the interval xrange, which approximate @@ -3871,6 +3885,16 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap [97, 499, 2681] """ from sage.plot.misc import setup_for_eval_on_grid + + f_actual = f + xrange_actual = xrange + if exp_dist: + if xrange[0] <= 0: + sage.misc.misc.verbose("Unable to perform exponential scale on negative range, clipping...", 1) + xrange[0] = 0.01 + f = lambda x: f_actual(exp(x)) + xrange = (log(xrange[0]), log(xrange[1])) + ignore, ranges = setup_for_eval_on_grid([], [xrange], plot_points) xmin, xmax, delta = ranges[0] data = srange(*ranges[0], include_endpoint=True) @@ -3960,4 +3984,8 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap sage.misc.misc.verbose("WARNING: When plotting, failed to evaluate function at %s points." % exceptions, level=0) sage.misc.misc.verbose("Last error message: '%s'" % msg, level=0) + if exp_dist: + for i in range(len(data)): + data[i] = (exp(data[i][0]), data[i][1]) + return data From 5897dfc3410ed8f584de7ea7a83e9b8170e5390c Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Tue, 21 Apr 2020 18:16:40 +0200 Subject: [PATCH 095/476] 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 096/476] 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 5d1a52e4c73c33f69aeae6ad9e42265750394adb Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 24 Apr 2020 11:41:19 +0200 Subject: [PATCH 097/476] store incidence matrix, if initialized from it --- .../combinatorial_polyhedron/base.pyx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 969c9f86db1..ab431210731 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -427,6 +427,12 @@ cdef class CombinatorialPolyhedron(SageObject): self._n_Hrepresentation = data.ncols() self._n_Vrepresentation = data.nrows() + # Store the incidence matrix. + if not data.is_immutable(): + data = data.__copy__() + data.set_immutable() + self.incidence_matrix.set_cache(data) + # Initializing the facets in their Bit-representation. self._bitrep_facets = incidence_matrix_to_bit_rep_of_facets(data) @@ -984,11 +990,22 @@ cdef class CombinatorialPolyhedron(SageObject): [0 0 0 1 1 1] [0 1 0 1 1 0] [0 1 1 1 0 0] - sage: P.incidence_matrix() == C.incidence_matrix() + + In this case the incidence matrix is only computed once:: + + sage: P.incidence_matrix() is C.incidence_matrix() + True + sage: C.incidence_matrix.clear_cache() + sage: C.incidence_matrix() is P.incidence_matrix() + False + sage: C.incidence_matrix() == P.incidence_matrix() True + :: + sage: P = polytopes.permutahedron(5) sage: C = P.combinatorial_polyhedron() + sage: C.incidence_matrix.clear_cache() sage: C.incidence_matrix() == P.incidence_matrix() True @@ -998,6 +1015,8 @@ cdef class CombinatorialPolyhedron(SageObject): sage: P = Polyhedron([[0,0]]) sage: P.incidence_matrix() [1 1] + sage: C = P.combinatorial_polyhedron() + sage: C.incidence_matrix.clear_cache() sage: P.combinatorial_polyhedron().incidence_matrix() [1 1] @@ -1006,9 +1025,11 @@ cdef class CombinatorialPolyhedron(SageObject): Check that :trac:`29455` is fixed:: sage: C = Polyhedron([[0]]).combinatorial_polyhedron() + sage: C.incidence_matrix.clear_cache() sage: C.incidence_matrix() [1] sage: C = CombinatorialPolyhedron(-1) + sage: C.incidence_matrix.clear_cache() sage: C.incidence_matrix() [] """ From 2ed055d22430d7866fd6e4b6f046b90dc9907fc3 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sat, 25 Apr 2020 15:12:27 +0200 Subject: [PATCH 098/476] 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 099/476] 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 100/476] 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 101/476] 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 102/476] 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 103/476] 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 104/476] 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 105/476] 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 106/476] 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 107/476] 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 108/476] 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 109/476] 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 a08db46dcc85650aafbe690b2d65a4f81d3efcf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 2 May 2020 11:40:17 +0200 Subject: [PATCH 110/476] some details in combinat about partitions --- src/sage/combinat/partition.py | 22 +++++++------ src/sage/combinat/set_partition_ordered.py | 36 ++++++++++++---------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index e046474e857..81b65fd422e 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -258,7 +258,7 @@ sage: Partition(frobenius_coordinates=([6,1],[2,0])) [7, 3, 1] sage: all(mu == Partition(frobenius_coordinates=mu.frobenius_coordinates()) - ....: for n in range(30) for mu in Partitions(n)) + ....: for n in range(12) for mu in Partitions(n)) True We use the lexicographic ordering:: @@ -282,12 +282,11 @@ from __future__ import print_function, absolute_import from copy import copy -import six -from six.moves import range, zip from sage.libs.all import pari from sage.libs.flint.arith import number_of_partitions as flint_number_of_partitions +from sage.arith.misc import multinomial from sage.structure.global_options import GlobalOptions from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -325,6 +324,7 @@ from sage.graphs.dot2tex_utils import have_dot2tex from sage.functions.other import binomial + class Partition(CombinatorialElement): r""" A partition `p` of a nonnegative integer `n` is a @@ -2804,12 +2804,14 @@ def top_garnir_tableau(self,e,cell): g=self.garnir_tableau(cell) # start with the Garnir tableau and modify - if e==0: return g # no more dominant tableau of the same residue + if e==0: + return g # no more dominant tableau of the same residue a=e*int((self[row]-col)/e) # number of cells in the e-bricks in row `row` b=e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` - if a==0 or b==0: return g + if a==0 or b==0: + return g t=g.to_list() m=g[row+1][0] # smallest number in 0-Garnir belt @@ -3670,8 +3672,8 @@ def centralizer_size(self, t=0, q=0): sage: Partition([2,2,2]).aut() 48 """ - size = prod(i ** mi * factorial(mi) - for i, mi in six.iteritems(self.to_exp_dict())) + size = prod(i**mi * factorial(mi) + for i, mi in self.to_exp_dict().items()) if t or q: size *= prod((ZZ.one() - q ** j) / (ZZ.one() - t ** j) for j in self) @@ -4349,7 +4351,7 @@ def is_core(self, k): :meth:`core`, :class:`Core` """ - return not k in self.hooks() + return k not in self.hooks() def k_interior(self, k): r""" @@ -5109,7 +5111,7 @@ def multinomial_with_partitions(sizes,path_counts): # if we know the total length alloted for each of the paths (sizes), and the number # of paths for each component. A multinomial picks the ordering of the components where # each step is taken. - return prod(path_counts) * factorial(sum(sizes)) / prod([factorial(_) for _ in sizes]) + return prod(path_counts) * multinomial(sizes) sizes = [larger_quotients[i].size()-smaller_quotients[i].size() for i in range(k)] path_counts = [larger_quotients[i].dimension(smaller_quotients[i]) for i in range(k)] @@ -6228,7 +6230,7 @@ def from_core_and_quotient(self, core, quotient): True """ from .partition_tuple import PartitionTuple, PartitionTuples - if not quotient in PartitionTuples(): + if quotient not in PartitionTuples(): raise ValueError('the quotient %s must be a tuple of partitions'%quotient) components = PartitionTuple(quotient).components() length = len(components) diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 70408ad52f1..791dfa13e09 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -10,7 +10,7 @@ - Travis Scrimshaw (2013-02-28): Removed ``CombinatorialClass`` and added entry point through :class:`OrderedSetPartition`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -23,16 +23,15 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from six import add_metaclass -from sage.arith.all import factorial +from sage.arith.all import factorial, multinomial from sage.sets.set import Set, Set_generic from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.all import prod from sage.structure.parent import Parent from sage.structure.element import parent from sage.structure.unique_representation import UniqueRepresentation @@ -185,10 +184,11 @@ def __classcall_private__(cls, parts=None, from_word=None): if from_word: return OrderedSetPartitions().from_finite_word(Words()(from_word)) # if `parts` looks like a sequence of "letters" then treat it like a word. - if parts in Words() or (len(parts) > 0 and (parts[0] in ZZ or isinstance(parts[0], str))): + if parts in Words() or (len(parts) and (parts[0] in ZZ or isinstance(parts[0], str))): return OrderedSetPartitions().from_finite_word(Words()(parts)) else: - P = OrderedSetPartitions( reduce(lambda x,y: x.union(y), map(Set, parts), Set([])) ) + P = OrderedSetPartitions(reduce(lambda x,y: x.union(y), + map(Set, parts), Set([]))) return P.element_class(P, parts) def __init__(self, parent, s): @@ -204,7 +204,6 @@ def __init__(self, parent, s): self._base_set = reduce(lambda x,y: x.union(y), map(Set, s), Set([])) ClonableArray.__init__(self, parent, [Set(_) for _ in s]) - def _repr_(self): """ Return a string representation of ``self``. @@ -368,8 +367,8 @@ def reversed(self): sage: OrderedSetPartition([]).reversed() [] """ - par = parent(self) - return par(list(reversed(list(self)))) + par = self.parent() + return par(list(reversed(self))) def complement(self): r""" @@ -479,7 +478,7 @@ def is_finer(self, co2): """ co1 = self if co1.base_set() != co2.base_set(): - raise ValueError("ordered set partitions self (= %s) and co2 (= %s) must be of the same set"%(self, co2)) + raise ValueError("ordered set partitions self (= %s) and co2 (= %s) must be of the same set" % (self, co2)) i1 = 0 for j2 in co2: @@ -665,7 +664,6 @@ def strongly_finer(self): return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) - def is_strongly_finer(self, co2): r""" Return ``True`` if the ordered set partition ``self`` is strongly @@ -766,7 +764,8 @@ def strongly_fatter(self): g = [-1] + [i for i in range(l-1) if c[i][-1] > c[i+1][0]] + [l-1] # g lists the positions of the blocks that cannot be merged # with their right neighbors. - subcomps = [OrderedSetPartition(c[g[i] + 1 : g[i+1] + 1]) for i in range(len(g)-1)] + subcomps = [OrderedSetPartition(c[g[i] + 1: g[i + 1] + 1]) + for i in range(len(g) - 1)] # Now, self is the concatenation of the entries of subcomps. # We can fatten each of the ordered set partitions setcomps # arbitrarily, and then concatenate the results. @@ -903,7 +902,7 @@ def __classcall_private__(cls, s=None, c=None): if isinstance(c, (int, Integer)): return OrderedSetPartitions_sn(s, c) if c not in Compositions(len(s)): - raise ValueError("c must be a composition of %s"%len(s)) + raise ValueError("c must be a composition of %s" % len(s)) return OrderedSetPartitions_scomp(s, Composition(c)) def __init__(self, s): @@ -929,7 +928,7 @@ def _element_constructor_(self, s): [{1, 3}, {2, 4}] """ if isinstance(s, OrderedSetPartition): - raise ValueError("cannot convert %s into an element of %s"%(s, self)) + raise ValueError("cannot convert %s into an element of %s" % (s, self)) return self.element_class(self, list(s)) Element = OrderedSetPartition @@ -1057,6 +1056,7 @@ def __iter__(self): for z in OrderedSetPartitions(self._set, x): yield self.element_class(self, z) + class OrderedSetPartitions_sn(OrderedSetPartitions): def __init__(self, s, n): """ @@ -1194,7 +1194,7 @@ def cardinality(self): sage: OrderedSetPartitions(5, [2,0,3]).cardinality() 10 """ - return factorial(len(self._set)) / prod([factorial(i) for i in self.c]) + return multinomial(self.c) def __iter__(self): """ @@ -1252,6 +1252,7 @@ def __iter__(self): yield self.element_class(self, [Set(res[dcomp[i]+1:dcomp[i+1]+1]) for i in range(l)]) + class OrderedSetPartitions_all(OrderedSetPartitions): r""" Ordered set partitions of `\{1, \ldots, n\}` for all @@ -1298,9 +1299,9 @@ def _element_constructor_(self, s): """ if isinstance(s, OrderedSetPartition): gset = s.parent()._set - if gset == frozenset(range(1,len(gset)+1)): + if gset == frozenset(range(1, len(gset) + 1)): return self.element_class(self, list(s)) - raise ValueError("cannot convert %s into an element of %s"%(s, self)) + raise ValueError("cannot convert %s into an element of %s" % (s, self)) return self.element_class(self, list(s)) def __contains__(self, x): @@ -1408,5 +1409,6 @@ def __setstate__(self, state): k = state['_k'] OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k,n-k)) + from sage.misc.persist import register_unpickle_override register_unpickle_override("sage.combinat.split_nk", "SplitNK_nk", SplitNK) From f4c8064c0c14726d802076d1475c36e477eaa24a Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 2 May 2020 21:54:58 +0200 Subject: [PATCH 111/476] 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 112/476] 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 584f22f4760ffea1fbe0f6408541d6ac6c48513f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 3 May 2020 10:55:58 +0200 Subject: [PATCH 113/476] some details in Lyndon words (pep, code and doc) --- src/sage/combinat/words/lyndon_word.py | 71 +++++++++++++------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index 26c9f32268c..a0539d49685 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -12,15 +12,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from __future__ import absolute_import -from six.moves import builtins from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.combinat.composition import Composition, Compositions from sage.rings.all import Integer -from sage.arith.all import factorial, divisors, gcd, moebius -from sage.misc.all import prod +from sage.arith.all import divisors, gcd, moebius, multinomial from sage.combinat.necklace import _sfc from sage.combinat.words.words import FiniteWords @@ -29,24 +27,26 @@ def LyndonWords(e=None, k=None): """ - Returns the combinatorial class of Lyndon words. + Return the combinatorial class of Lyndon words. A Lyndon word `w` is a word that is lexicographically less than all of its rotations. Equivalently, whenever `w` is split into two non-empty substrings, `w` is lexicographically less than the right substring. + See :wikipedia:`Lyndon_word` + INPUT: - no input at all or - - ``e`` - integer, size of alphabet - - ``k`` - integer, length of the words + - ``e`` -- integer, size of alphabet + - ``k`` -- integer, length of the words or - - ``e`` - a composition + - ``e`` -- a composition OUTPUT: @@ -95,15 +95,16 @@ def LyndonWords(e=None, k=None): raise TypeError("e must be a positive integer or a composition") + def LyndonWord(data, check=True): r""" Construction of a Lyndon word. INPUT: - - ``data`` - list - - ``check`` - bool (optional, default: True) if True, a - verification that the input data represent a Lyndon word. + - ``data`` -- list + - ``check`` -- bool (optional, default: ``True``) if ``True``, + check that the input data represents a Lyndon word. OUTPUT: @@ -120,13 +121,14 @@ def LyndonWord(data, check=True): ... ValueError: not a Lyndon word - If check is False, then no verification is done:: + If ``check`` is ``False``, then no verification is done:: sage: LyndonWord([2,1,2,3], check=False) word: 2123 """ return LyndonWords()(data, check=check) + class LyndonWords_class(UniqueRepresentation, Parent): r""" The set of all Lyndon words. @@ -186,6 +188,7 @@ def __contains__(self, w): w = self._words(w) return w.is_lyndon() + class LyndonWords_evaluation(UniqueRepresentation, Parent): r""" The set of Lyndon words on a fixed multiset of letters. @@ -223,7 +226,7 @@ def __repr__(self): sage: repr(LyndonWords([2,1,1])) 'Lyndon words with evaluation [2, 1, 1]' """ - return "Lyndon words with evaluation %s"%self._e + return "Lyndon words with evaluation %s" % self._e def __call__(self, *args, **kwds): r""" @@ -265,7 +268,7 @@ def __contains__(self, x): def cardinality(self): """ - Returns the number of Lyndon words with the evaluation e. + Return the number of Lyndon words with the evaluation e. EXAMPLES:: @@ -277,9 +280,7 @@ def cardinality(self): 30 Check to make sure that the count matches up with the number of - Lyndon words generated. - - :: + Lyndon words generated:: sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] @@ -287,13 +288,12 @@ def cardinality(self): True """ evaluation = self._e - le = builtins.list(evaluation) - if len(evaluation) == 0: - return 0 - + le = list(evaluation) + if not evaluation: + return Integer(0) n = sum(evaluation) - - return sum([moebius(j)*factorial(n/j) / prod([factorial(ni/j) for ni in evaluation]) for j in divisors(gcd(le))])/n + return sum(moebius(j) * multinomial([ni // j for ni in evaluation]) + for j in divisors(gcd(le))) // n def __iter__(self): """ @@ -331,19 +331,16 @@ def __iter__(self): """ if not self._e: return - k = 0 while self._e[k] == 0: k += 1 - for z in _sfc(self._e[k:], equality=True): - yield self._words([i+k+1 for i in z], check=False) + yield self._words([i + k + 1 for i in z], check=False) class LyndonWords_nk(UniqueRepresentation, Parent): r""" - Lyndon words of fixed length `k` over the alphabet - `\{1, 2, \ldots, n\}`. + Lyndon words of fixed length `k` over the alphabet `\{1, 2, \ldots, n\}`. INPUT: @@ -392,7 +389,7 @@ def __repr__(self): sage: repr(LyndonWords(2, 3)) 'Lyndon words from an alphabet of size 2 of length 3' """ - return "Lyndon words from an alphabet of size %s of length %s"%(self._n, self._k) + return "Lyndon words from an alphabet of size %s of length %s" % (self._n, self._k) def __call__(self, *args, **kwds): r""" @@ -445,8 +442,8 @@ def cardinality(self): else: s = Integer(0) for d in divisors(self._k): - s += moebius(d)*(self._n**(self._k/d)) - return s/self._k + s += moebius(d) * self._n**(self._k // d) + return s // self._k def __iter__(self): """ @@ -469,14 +466,17 @@ def __iter__(self): """ W = self._words._element_classes['list'] for lw in lyndon_word_iterator(self._n, self._k): - yield W(self._words, [i+1 for i in lw]) + yield W(self._words, [i + 1 for i in lw]) + def StandardBracketedLyndonWords(n, k): """ - Returns the combinatorial class of standard bracketed Lyndon words - from [1, ..., n] of length k. These are in one to one - correspondence with the Lyndon words and form a basis for the - subspace of degree k of the free Lie algebra of rank n. + Return the combinatorial class of standard bracketed Lyndon words + from [1, ..., n] of length k. + + These are in one to one correspondence with the Lyndon words and + form a basis for the subspace of degree k of the free Lie algebra + of rank n. EXAMPLES:: @@ -581,4 +581,3 @@ def standard_bracketing(lw): for i in range(1, len(lw)): if lw[i:] in LyndonWords(): return [standard_bracketing(lw[:i]), standard_bracketing(lw[i:])] - From 6fd708e2a4df5dd83dd08bcd8dfe08b448bed9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 3 May 2020 11:08:57 +0200 Subject: [PATCH 114/476] trac 29634 some further details --- src/sage/combinat/set_partition_ordered.py | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 791dfa13e09..731f159b117 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -184,11 +184,11 @@ def __classcall_private__(cls, parts=None, from_word=None): if from_word: return OrderedSetPartitions().from_finite_word(Words()(from_word)) # if `parts` looks like a sequence of "letters" then treat it like a word. - if parts in Words() or (len(parts) and (parts[0] in ZZ or isinstance(parts[0], str))): + if parts in Words() or (parts and (parts[0] in ZZ or isinstance(parts[0], str))): return OrderedSetPartitions().from_finite_word(Words()(parts)) else: - P = OrderedSetPartitions(reduce(lambda x,y: x.union(y), - map(Set, parts), Set([]))) + P = OrderedSetPartitions(reduce(lambda x, y: x.union(y), + parts, frozenset())) return P.element_class(P, parts) def __init__(self, parent, s): @@ -201,7 +201,7 @@ def __init__(self, parent, s): sage: s = OS([[1, 3], [2, 4]]) sage: TestSuite(s).run() """ - self._base_set = reduce(lambda x,y: x.union(y), map(Set, s), Set([])) + self._base_set = reduce(lambda x, y: x.union(y), map(Set, s), Set([])) ClonableArray.__init__(self, parent, [Set(_) for _ in s]) def _repr_(self): @@ -367,7 +367,7 @@ def reversed(self): sage: OrderedSetPartition([]).reversed() [] """ - par = self.parent() + par = parent(self) return par(list(reversed(self))) def complement(self): @@ -760,8 +760,8 @@ def strongly_fatter(self): [[{4}, {1, 5}, {3}], [{4}, {1}, {5}, {3}]] """ c = [sorted(X) for X in self] - l = len(c) - g = [-1] + [i for i in range(l-1) if c[i][-1] > c[i+1][0]] + [l-1] + l = len(c) - 1 + g = [-1] + [i for i in range(l) if c[i][-1] > c[i + 1][0]] + [l] # g lists the positions of the blocks that cannot be merged # with their right neighbors. subcomps = [OrderedSetPartition(c[g[i] + 1: g[i + 1] + 1]) @@ -953,21 +953,21 @@ def __contains__(self, x): if not isinstance(x, (OrderedSetPartition, list, tuple)): return False - #The total number of elements in the list - #should be the same as the number is self._set + # The total number of elements in the list + # should be the same as the number is self._set if sum(map(len, x)) != len(self._set): return False - #Check to make sure each element of the list - #is a nonempty set + # Check to make sure each element of the list + # is a nonempty set u = Set([]) for s in x: if not s or not isinstance(s, (set, frozenset, Set_generic)): return False u = u.union(s) - #Make sure that the union of all the - #sets is the original set + # Make sure that the union of all the + # sets is the original set if u != Set(self._set): return False @@ -1130,7 +1130,7 @@ def __iter__(self): [{3}, {1, 2, 4}], [{4}, {1, 2, 3}]] """ - for x in Compositions(len(self._set),length=self.n): + for x in Compositions(len(self._set), length=self.n): for z in OrderedSetPartitions_scomp(self._set, x): yield self.element_class(self, z) @@ -1407,7 +1407,7 @@ def __setstate__(self, state): self.__class__ = OrderedSetPartitions_scomp n = state['_n'] k = state['_k'] - OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k,n-k)) + OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k, n-k)) from sage.misc.persist import register_unpickle_override From 49ba962924b6876a577c44916d8ed55df7f432d2 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 3 Apr 2019 02:31:54 +0200 Subject: [PATCH 115/476] rebase and correct --- src/sage/combinat/sf/elementary.py | 117 +++++++++++++++++++++++++- src/sage/combinat/sf/homogeneous.py | 115 ++++++++++++++++++++++++++ src/sage/combinat/sf/monomial.py | 88 ++++++++++++++++++++ src/sage/combinat/sf/powersum.py | 116 ++++++++++++++++++++++++++ src/sage/combinat/sf/schur.py | 100 ++++++++++++++++++++++- src/sage/combinat/sf/sfa.py | 122 +++++++++++++++++++++++++++- 6 files changed, 655 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index f65ea34ed69..34e91173027 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -20,7 +20,10 @@ #***************************************************************************** from . import multiplicative, classical from sage.combinat.partition import Partition - +from sage.misc.all import prod +from sage.functions.other import factorial, binomial +from sage.rings.all import infinity +from sage.combinat.q_analogues import q_binomial, q_factorial ################################### # # @@ -305,6 +308,118 @@ def expand(self, n, alphabet='x'): condition = lambda part: max(part) > n return self._expand(condition, n, alphabet) + + def principal_specialization(self, n=infinity, q=None): + r""" + Return the principal specialization of the symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring + homomorphism given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, + the default is to create the fraction field of + polynomials in ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).e() + sage: x = e[3,1] + sage: x.principal_specialization(3) + q^5 + q^4 + q^3 + sage: x = 5*e[1,1,1] + 3*e[2,1] + 1 + sage: x.principal_specialization(3) + 5*q^6 + 18*q^5 + 36*q^4 + 44*q^3 + 36*q^2 + 18*q + 6 + + By default, we return a rational functions in q. Sometimes it is + it is better to obtain an element of the symbolic ring:: + + sage: x.principal_specialization(q=var("q")) + -3*q/((q^2 - 1)*(q - 1)^2) - 5/(q - 1)^3 + 1 + + TESTS:: + + sage: e.zero().principal_specialization(3) + 0 + + """ + if q is None: + q = self.base_ring()["q"].fraction_field().gen() + if q == 1: + f = lambda partition: prod(binomial(n, part) for part in partition) + elif n == infinity: + f = lambda partition: prod(q**binomial(part, 2)/prod((1-q**i) + for i in range(1,part+1)) + for part in partition) + else: + f = lambda partition: prod(q**binomial(part, 2)*q_binomial(n, part, q=q) + for part in partition) + + return self.parent()._apply_module_morphism(self, f, q.parent()) + + + def exponential_specialization(self, t=None, q=1): + r""" + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).e() + sage: x = e[3,2] + sage: x.exponential_specialization() + 1/12*t^5 + sage: x = 5*e[2] + 3*e[1] + 1 + sage: x.exponential_specialization(t=var("t"), q=var("q")) + 5*q*t^2/(q + 1) + 3*t + 1 + + TESTS:: + + sage: e.zero().exponential_specialization() + 0 + + """ + if q == 1: + if t is None: + t = self.base_ring()["t"].gen() + def f(partition): + n = 0 + m = 1 + for part in partition: + n += part + m *= factorial(part) + return t**n/m + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + if q is None and t is None: + Rq = self.base_ring()["q"].fraction_field() + q = Rq.gen() + t = Rq["t"].gen() + elif q is None: + q = t.parent()["q"].fraction_field().gen() + elif t is None: + t = q.parent()["t"].gen() + + def f(partition): + n = 0 + m = 1 + for part in partition: + n += part + m *= q**binomial(part, 2)/q_factorial(part, q=q) + + return t**n * m + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.elementary', 'SymmetricFunctionAlgebraElement_elementary', SymmetricFunctionAlgebra_elementary.Element) diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 3e5462d1742..618e136f9ee 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -28,6 +28,10 @@ #################################### from . import multiplicative, classical from sage.combinat.partition import Partition +from sage.rings.all import infinity +from sage.misc.all import prod +from sage.functions.other import factorial, binomial +from sage.combinat.q_analogues import q_binomial, q_factorial class SymmetricFunctionAlgebra_homogeneous(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): @@ -223,6 +227,117 @@ def expand(self, n, alphabet='x'): condition = lambda part: False return self._expand(condition, n, alphabet) + def principal_specialization(self, n=infinity, q=None): + r""" + Return the principal specialization of the symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring + homomorphism given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, + the default is to create the fraction field of + polynomials in ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: x = h[2,1] + sage: x.principal_specialization(3) + q^6 + 2*q^5 + 4*q^4 + 4*q^3 + 4*q^2 + 2*q + 1 + sage: x = 3*h[2] + 2*h[1] + 1 + sage: x.principal_specialization(3, q=var("q")) + 2*(q^3 - 1)/(q - 1) + 3*(q^4 - 1)*(q^3 - 1)/((q^2 - 1)*(q - 1)) + 1 + + TESTS:: + + sage: x = h.zero() + sage: s = x.principal_specialization(3); s + 0 + + """ + if q is None: + q = self.base_ring()["q"].fraction_field().gen() + if q == 1: + f = lambda partition: prod(binomial(n+part-1, part) for part in partition) + elif n == infinity: + f = lambda partition: prod(1/prod((1-q**i) for i in range(1, part+1)) for part in partition) + else: + f = lambda partition: prod(q_binomial(n+part-1, part, q=q) for part in partition) + + return self.parent()._apply_module_morphism(self, f, q.parent()) + + + def exponential_specialization(self, t=None, q=1): + r""" + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: x = h[5,3] + sage: x.exponential_specialization() + 1/720*t^8 + sage: factorial(5)*factorial(3) + 720 + + sage: x = 5*h[1,1,1] + 3*h[2,1] + 1 + sage: x.exponential_specialization() + 13/2*t^3 + 1 + + We also support the `q`-exponential_specialization:: + + sage: factor(h[3].exponential_specialization(q=var("q"), t=var("t"))) + t^3/((q^2 + q + 1)*(q + 1)) + + TESTS:: + + sage: x = h.zero() + sage: s = x.exponential_specialization(); s + 0 + + """ + if q == 1: + if t is None: + t = self.base_ring()["t"].gen() + def f(partition): + n = 0 + m = 1 + for part in partition: + n += part + m *= factorial(part) + return t**n/m + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + if q is None and t is None: + Rq = self.base_ring()["q"].fraction_field() + q = Rq.gen() + t = Rq["t"].gen() + elif q is None: + q = t.parent()["q"].fraction_field().gen() + elif t is None: + t = q.parent()["t"].gen() + + def f(partition): + n = 0 + m = 1 + for part in partition: + n += part + m *= q_factorial(part, q=q) + return t**n/m + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.homogeneous', 'SymmetricFunctionAlgebraElement_homogeneous', SymmetricFunctionAlgebra_homogeneous.Element) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 01cc7e73d5f..28097b92dd8 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -22,7 +22,10 @@ from . import classical import sage.libs.symmetrica.all as symmetrica from sage.rings.integer import Integer +from sage.rings.infinity import infinity from sage.combinat.partition import Partition, _Partitions +from sage.functions.other import factorial, binomial +from sage.arith.misc import multinomial class SymmetricFunctionAlgebra_monomial(classical.SymmetricFunctionAlgebra_classical): @@ -312,6 +315,91 @@ def condition(part): return len(part) > n return self._expand(condition, n, alphabet) +<<<<<<< HEAD +======= + def principal_specialization(self, n=infinity, q=None): + r""" + Return the principal specialization of the symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring + homomorphism given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, + the default is to create the fraction field of + polynomials in ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: m = SymmetricFunctions(QQ).m() + sage: x = m[3,1] + sage: x.principal_specialization(3) + q^7 + q^6 + q^5 + q^3 + q^2 + q + + sage: x = 5*m[2] + 3*m[1] + 1 + sage: x.principal_specialization(3, q=var("q")) + 5*(q^6 - 1)/(q^2 - 1) + 3*(q^3 - 1)/(q - 1) + 1 + + TESTS:: + + sage: m.zero().principal_specialization(3) + 0 + + """ + if q == 1: + f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) + return self.parent()._apply_module_morphism(self, f, q.parent()) + + return self.parent().realization_of().powersum()(self).principal_specialization(n=n, q=q) + + def exponential_specialization(self, t=None, q=1): + r""" + EXAMPLES:: + + sage: m = SymmetricFunctions(QQ).m() + sage: (m[3]+m[2,1]+m[1,1,1]).exponential_specialization() + 1/6*t^3 + + sage: x = 5*m[1,1,1] + 3*m[2,1] + 1 + sage: x.exponential_specialization() + 5/6*t^3 + 1 + + We also support the `q`-exponential_specialization:: + + sage: factor(m[3].exponential_specialization(q=var("q"), t=var("t"))) + (q - 1)^2*t^3/(q^2 + q + 1) + + TESTS:: + + sage: m.zero().exponential_specialization() + 0 + + """ + if q == 1: + if t is None: + t = self.base_ring()["t"].gen() + def f(partition): + n = 0 + for part in partition: + if part != 1: + return 0 + n += 1 + return t**n/factorial(n) + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + return self.parent().realization_of().powersum()(self).exponential_specialization(t=t, q=q) +>>>>>>> rebase and correct # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 80d820ace7a..6cc6ac2a68c 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -21,6 +21,8 @@ from . import sfa, multiplicative, classical from sage.combinat.partition import Partition from sage.arith.all import divisors +from sage.rings.all import infinity +from sage.misc.all import prod class SymmetricFunctionAlgebra_power(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): @@ -704,6 +706,120 @@ def eval_at_permutation_roots(self, rho): p.eval_at_permutation_roots_on_generators(k, rho) for k in lam) return p._apply_module_morphism(self, on_basis, R) + def principal_specialization(self, n=infinity, q=None): + r"""Return the principal specialization of the symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring + homomorphism given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, + the default is to create the fraction field of + polynomials in ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: p = SymmetricFunctions(QQ).p() + sage: x = p[8,7,3,1] + sage: x.principal_specialization(3, q=var("q")) + (q^24 - 1)*(q^21 - 1)*(q^9 - 1)/((q^8 - 1)*(q^7 - 1)*(q - 1)) + + sage: x = 5*p[1,1,1] + 3*p[2,1] + 1 + sage: x.principal_specialization(3, q=var("q")) + 5*(q^3 - 1)^3/(q - 1)^3 + 3*(q^6 - 1)*(q^3 - 1)/((q^2 - 1)*(q - 1)) + 1 + + By default, we return a rational function in `q`:: + + sage: x.principal_specialization(3) + 8*q^6 + 18*q^5 + 36*q^4 + 38*q^3 + 36*q^2 + 18*q + 9 + + If ``n`` is not given we return the stable principal specialisation:: + + sage: x.principal_specialization(q=var("q")) + 3/((q^2 - 1)*(q - 1)) - 5/(q - 1)^3 + 1 + + TESTS:: + + sage: p.zero().principal_specialization(3) + 0 + + """ + if q is None: + q = self.base_ring()["q"].fraction_field().gen() + if q == 1: + f = lambda partition: n**len(partition) + elif n == infinity: + f = lambda partition: prod(1/(1-q**part) for part in partition) + else: + f = lambda partition: prod((1-q**(n*part))/(1-q**part) for part in partition) + + return self.parent()._apply_module_morphism(self, f, q.parent()) + + def exponential_specialization(self, t=None, q=1): + r""" + EXAMPLES:: + + sage: p = SymmetricFunctions(QQ).p() + sage: x = p[8,7,3,1] + sage: x.exponential_specialization() + 0 + sage: x = p[3] + 5*p[1,1] + 2*p[1] + 1 + sage: x.exponential_specialization(t=var("t")) + 5*t^2 + 2*t + 1 + + We also support the `q`-exponential_specialization:: + + sage: factor(p[3].exponential_specialization(q=var("q"), t=var("t"))) + (q - 1)^2*t^3/(q^2 + q + 1) + + TESTS:: + + sage: p.zero().exponential_specialization() + 0 + + """ + if q == 1: + if t is None: + t = self.base_ring()["t"].gen() + def f(partition): + n = 0 + for part in partition: + if part != 1: + return 0 + n += 1 + return t**n + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + if q is None and t is None: + Rq = self.base_ring()["q"].fraction_field() + q = Rq.gen() + t = Rq["t"].gen() + elif q is None: + q = t.parent()["q"].fraction_field().gen() + elif t is None: + t = q.parent()["t"].gen() + + def f(partition): + n = 0 + m = 1 + for part in partition: + n += part + m *= 1-q**part + return (1-q)**n * t**n / m + + return self.parent()._apply_module_morphism(self, f, t.parent()) + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.powersum', 'SymmetricFunctionAlgebraElement_power', SymmetricFunctionAlgebra_power.Element) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index d193157aa3e..745de3b3dfc 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -21,7 +21,10 @@ from . import classical import sage.libs.lrcalc.lrcalc as lrcalc - +from sage.misc.all import prod +from sage.rings.infinity import infinity +from sage.functions.other import factorial +from sage.combinat.tableau import StandardTableaux class SymmetricFunctionAlgebra_schur(classical.SymmetricFunctionAlgebra_classical): def __init__(self, Sym): @@ -571,6 +574,101 @@ def expand(self, n, alphabet='x'): condition = lambda part: len(part) > n return self._expand(condition, n, alphabet) + def principal_specialization(self, n=infinity, q=None): + r""" + Return the principal specialization of the symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring + homomorphism given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, + the default is to create the fraction field of + polynomials in ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: x = s[2] + sage: x.principal_specialization(3) + q^4 + q^3 + 2*q^2 + q + 1 + + sage: x = 3*s[2,2] + 2*s[1] + 1 + sage: x.principal_specialization(3, q=var("q")) + 3*(q^4 - 1)*(q^3 - 1)*q^2/((q^2 - 1)*(q - 1)) + 2*(q^3 - 1)/(q - 1) + 1 + + sage: x.principal_specialization(q=var("q")) + -2/(q - 1) + 3*q^2/((q^3 - 1)*(q^2 - 1)^2*(q - 1)) + 1 + + TESTS:: + + sage: s.zero().principal_specialization(3) + 0 + + """ + if q is None: + q = self.base_ring()["q"].fraction_field().gen() + if q == 1: + f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) + / prod(h for h in partition.hooks())) + elif n == infinity: + f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) + / prod(1-q**h for h in partition.hooks())) + else: + f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) + * prod(1-q**(n + partition.content(*c)) for c in partition.cells()) + / prod(1-q**h for h in partition.hooks())) + + return self.parent()._apply_module_morphism(self, f, q.parent()) + + + def exponential_specialization(self, t=None, q=1): + r""" + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: x = s[5,3] + sage: x.exponential_specialization() + 1/1440*t^8 + + sage: x = 5*s[1,1,1] + 3*s[2,1] + 1 + sage: x.exponential_specialization() + 11/6*t^3 + 1 + + We also support the `q`-exponential_specialization:: + + sage: factor(s[3].exponential_specialization(q=var("q"), t=var("t"))) + t^3/((q^2 + q + 1)*(q + 1)) + + TESTS:: + + sage: s.zero().exponential_specialization() + 0 + + """ + if q == 1: + if t is None: + t = self.base_ring()["t"].gen() + def f(partition): + n = partition.size() + return (StandardTableaux(partition).cardinality() + * t**n / factorial(n)) + + return self.parent()._apply_module_morphism(self, f, t.parent()) + + return self.parent().realization_of().powersum()(self).exponential_specialization(t=t, q=q) + + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.schur', 'SymmetricFunctionAlgebraElement_schur', SymmetricFunctionAlgebra_schur.Element) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 35838d1cd01..cf9996339fe 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -213,7 +213,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.rings.all import Integer, PolynomialRing, QQ, ZZ +from sage.rings.all import Integer, PolynomialRing, QQ, ZZ, infinity from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.multi_polynomial import is_MPolynomial from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition @@ -5439,6 +5439,126 @@ def character_to_frobenius_image(self, n): return self.parent()(p.sum(self.eval_at_permutation_roots(rho) \ *p(rho)/rho.centralizer_size() for rho in Partitions(n))) + def principal_specialization(self, n=infinity, q=None): + r""" + Return the principal specialization of a symmetric function. + + The principal specialization of order `n` is the ring + homomorphism given by setting `x_i = q^i` for `i \in + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + + The stable principal specialization is the ring homomorphism + given by setting `x_i = q^i` for all `i`. + + INPUT: + + - ``n`` (default: ``infinity``) -- a nonnegative integer or + ``infinity``, specifying whether to compute the principal + specialization of order ``n`` or the stable principal + specialization. + + - ``q`` (default: ``None``) -- the value to use for `q`, the + default is to create the fraction field of polynomials in + ``q`` over the coefficient ring. + + EXAMPLES:: + + sage: m = SymmetricFunctions(QQ).m() + sage: x = m[1,1] + sage: x.principal_specialization(3) + q^3 + q^2 + q + + By default we return a rational function in ``q``. Sometimes + it is better to obtain an element of the symbolic ring:: + + sage: h = SymmetricFunctions(QQ).h() + sage: (h[3]+h[2]).principal_specialization(q=var("q")) + 1/((q^2 - 1)*(q - 1)) - 1/((q^3 - 1)*(q^2 - 1)*(q - 1)) + + TESTS:: + + sage: m = SymmetricFunctions(QQ).m() + sage: m.zero().principal_specialization(3) + 0 + + sage: x = 5*m[1,1,1] + 3*m[2,1] + 1 + sage: x.principal_specialization(3) + 3*q^5 + 6*q^4 + 5*q^3 + 6*q^2 + 3*q + 1 + + sage: B = SymmetricFunctions(QQ).realizations() + sage: x = m[2,1] + sage: len(set([b(x).principal_specialization(n=3) for b in B])) + 1 + sage: len(set([b(x).principal_specialization() for b in B])) + 1 + sage: len(set([b(x).principal_specialization(n=4, q=1) for b in B])) + 1 + sage: len(set([b(x).principal_specialization(n=4, q=2) for b in B])) + 1 + + """ + from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(self.parent().base_ring()).p() + return p(self).principal_specialization(n, q=q) + + + def exponential_specialization(self, t=None, q=1): + r"""Return the exponential specialization of a symmetric function. + + The `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + + EXAMPLES:: + + sage: m = SymmetricFunctions(QQ).m() + sage: (m[2,1]+m[1,1]).exponential_specialization() + 1/2*t^2 + + sage: x = m[3]+m[2,1]+m[1,1,1] + sage: d = x.homogeneous_degree() + sage: var("q t") + (q, t) + sage: factor((x.principal_specialization()*(1-q)^d*t^d)) + t^3/((q^2 + q + 1)*(q + 1)) + sage: factor(x.exponential_specialization(q=q, t=t)) + t^3/((q^2 + q + 1)*(q + 1)) + + TESTS:: + + sage: m = SymmetricFunctions(QQ).m() + sage: m.zero().exponential_specialization() + 0 + + sage: B = SymmetricFunctions(QQ).realizations() + sage: x = m[3]+m[2,1]+m[1,1,1] + sage: len(set([b(x).exponential_specialization(q=None, t=None) for b in B])) + 1 + sage: len(set([b(x).exponential_specialization(q=1) for b in B])) + 1 + sage: len(set([b(x).exponential_specialization(q=2) for b in B])) + 1 + sage: len(set([b(x).exponential_specialization(t=2) for b in B])) + 1 + + """ + p = self.parent().realization_of().powersum() + return p(self).exponential_specialization(t=t, q=q) + SymmetricFunctionAlgebra_generic.Element = SymmetricFunctionAlgebra_generic_Element From c1da94520b718d87edc567d4e08bdccc91b153b6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 3 Apr 2019 10:34:19 +0200 Subject: [PATCH 116/476] fix doctests --- src/sage/combinat/sf/sfa.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index cf9996339fe..e036e91c336 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5485,8 +5485,13 @@ def principal_specialization(self, n=infinity, q=None): sage: x.principal_specialization(3) 3*q^5 + 6*q^4 + 5*q^3 + 6*q^2 + 3*q + 1 - sage: B = SymmetricFunctions(QQ).realizations() - sage: x = m[2,1] + Check that the principal specializations in different bases + are all the same. When specific implementations for further + bases are added, this test should be adapted:: + + sage: S = SymmetricFunctions(QQ) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: m = S.m(); x = m[2,1] sage: len(set([b(x).principal_specialization(n=3) for b in B])) 1 sage: len(set([b(x).principal_specialization() for b in B])) @@ -5497,13 +5502,12 @@ def principal_specialization(self, n=infinity, q=None): 1 """ - from sage.combinat.sf.sf import SymmetricFunctions - p = SymmetricFunctions(self.parent().base_ring()).p() + p = self.parent().realization_of().powersum() return p(self).principal_specialization(n, q=q) - def exponential_specialization(self, t=None, q=1): - r"""Return the exponential specialization of a symmetric function. + r""" + Return the exponential specialization of a symmetric function. The `q`-exponential specialization is a ring homomorphism defined on homogeneous symmetric functions `f` of degree `n` @@ -5544,8 +5548,13 @@ def exponential_specialization(self, t=None, q=1): sage: m.zero().exponential_specialization() 0 - sage: B = SymmetricFunctions(QQ).realizations() - sage: x = m[3]+m[2,1]+m[1,1,1] + Check that the exponential specializations in different bases + are all the same. When specific implementations for further + bases are added, this test should be adapted:: + + sage: S = SymmetricFunctions(QQ) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: m = S.m(); x = m[3]+m[2,1]+m[1,1,1] sage: len(set([b(x).exponential_specialization(q=None, t=None) for b in B])) 1 sage: len(set([b(x).exponential_specialization(q=1) for b in B])) From d2fba34e79a9b64ffe60a1814d04fdc2bc6d8013 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 15 Apr 2019 19:27:49 +0200 Subject: [PATCH 117/476] add documentation --- src/sage/combinat/sf/elementary.py | 37 +++++++++++++++++++++++++++- src/sage/combinat/sf/homogeneous.py | 37 +++++++++++++++++++++++++++- src/sage/combinat/sf/monomial.py | 37 +++++++++++++++++++++++++++- src/sage/combinat/sf/powersum.py | 37 +++++++++++++++++++++++++++- src/sage/combinat/sf/schur.py | 38 ++++++++++++++++++++++++++++- src/sage/combinat/sf/sfa.py | 19 +++++++++++++-- 6 files changed, 198 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 34e91173027..06895b125d1 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -315,7 +315,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section + 7.8 of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -370,6 +371,40 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" + Return the exponential specialization of a symmetric function. + + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + EXAMPLES:: sage: e = SymmetricFunctions(QQ).e() diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 618e136f9ee..8b743939f9d 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -233,7 +233,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section + 7.8 of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -280,6 +281,40 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" + Return the exponential specialization of a symmetric function. + + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + EXAMPLES:: sage: h = SymmetricFunctions(QQ).h() diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 28097b92dd8..e9964b1ee09 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -323,7 +323,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section + 7.8 of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -364,6 +365,40 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" + Return the exponential specialization of a symmetric function. + + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + EXAMPLES:: sage: m = SymmetricFunctions(QQ).m() diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 6cc6ac2a68c..f26177c25be 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -711,7 +711,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section + 7.8 of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -767,6 +768,40 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" + Return the exponential specialization of a symmetric function. + + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + EXAMPLES:: sage: p = SymmetricFunctions(QQ).p() diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 745de3b3dfc..771eafb5ee1 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -580,7 +580,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section + 7.8 of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -634,6 +635,41 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" + Return the exponential specialization of a symmetric function. + + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism + defined on homogeneous symmetric functions `f` of degree `n` + as + + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + + .. MATH:: + + ex_q(f) = (1-q)^n t^n ps(f), + + where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. + + INPUT: + + - ``t`` (default: None) -- the value to use for `t`, the default + is to create the fraction field of polynomials in ``t`` + over the coefficient ring. + + - ``q`` (default: 1) -- the value to use for `q`. + + EXAMPLES:: sage: s = SymmetricFunctions(QQ).s() diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index e036e91c336..cd6e1cad5e9 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5445,7 +5445,8 @@ def principal_specialization(self, n=infinity, q=None): The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`. + \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section 7.8 + of [EnumComb2]_. The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. @@ -5509,15 +5510,29 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The `q`-exponential specialization is a ring homomorphism + The exponential specialization `ex` is the ring homomorphism + defined on the basis of powersum symmetric functions by + setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, + on the basis of homogeneous functions it is given by `ex(h_n) + = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + + By analogy `q`-exponential specialization is a ring homomorphism defined on homogeneous symmetric functions `f` of degree `n` as + .. MATH:: + + ex_q(h_n) = t^n / [n]_q!, + + where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + .. MATH:: ex_q(f) = (1-q)^n t^n ps(f), where `ps(f)` is the stable principal specialisation of `f`. + Note that setting `q = 1` in the stable principal + specialisation is an invalid operation. INPUT: From dd7e42267265f4789e28c33398411132c23d8542 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 3 Dec 2019 22:25:57 +0100 Subject: [PATCH 118/476] raise error if q is in the base ring, add comment about plethysm --- src/sage/combinat/sf/elementary.py | 14 ++++++++++++-- src/sage/combinat/sf/homogeneous.py | 14 ++++++++++++-- src/sage/combinat/sf/monomial.py | 7 ++++++- src/sage/combinat/sf/powersum.py | 14 ++++++++++++-- src/sage/combinat/sf/schur.py | 14 ++++++++++++-- src/sage/combinat/sf/sfa.py | 24 ++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 06895b125d1..6c939b954c3 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -355,7 +355,12 @@ def principal_specialization(self, n=infinity, q=None): """ if q is None: - q = self.base_ring()["q"].fraction_field().gen() + try: + self.base_ring()('q') + except TypeError: + q = self.base_ring()["q"].gen() + else: + raise ValueError("the variable q is in the base ring, pass it explicitely") if q == 1: f = lambda partition: prod(binomial(n, part) for part in partition) elif n == infinity: @@ -423,7 +428,12 @@ def exponential_specialization(self, t=None, q=1): """ if q == 1: if t is None: - t = self.base_ring()["t"].gen() + try: + self.base_ring()('t') + except TypeError: + t = self.base_ring()["t"].gen() + else: + raise ValueError("the variable t is in the base ring, pass it explicitely") def f(partition): n = 0 m = 1 diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 8b743939f9d..2f4f9b9bd08 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -268,7 +268,12 @@ def principal_specialization(self, n=infinity, q=None): """ if q is None: - q = self.base_ring()["q"].fraction_field().gen() + try: + self.base_ring()('q') + except TypeError: + q = self.base_ring()["q"].gen() + else: + raise ValueError("the variable q is in the base ring, pass it explicitely") if q == 1: f = lambda partition: prod(binomial(n+part-1, part) for part in partition) elif n == infinity: @@ -342,7 +347,12 @@ def exponential_specialization(self, t=None, q=1): """ if q == 1: if t is None: - t = self.base_ring()["t"].gen() + try: + self.base_ring()('t') + except TypeError: + t = self.base_ring()["t"].gen() + else: + raise ValueError("the variable t is in the base ring, pass it explicitely") def f(partition): n = 0 m = 1 diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index e9964b1ee09..afa935d53c1 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -422,7 +422,12 @@ def exponential_specialization(self, t=None, q=1): """ if q == 1: if t is None: - t = self.base_ring()["t"].gen() + try: + self.base_ring()('t') + except TypeError: + t = self.base_ring()["t"].gen() + else: + raise ValueError("the variable t is in the base ring, pass it explicitely") def f(partition): n = 0 for part in partition: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index f26177c25be..d72c2ce9b9c 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -756,7 +756,12 @@ def principal_specialization(self, n=infinity, q=None): """ if q is None: - q = self.base_ring()["q"].fraction_field().gen() + try: + self.base_ring()('q') + except TypeError: + q = self.base_ring()["q"].gen() + else: + raise ValueError("the variable q is in the base ring, pass it explicitely") if q == 1: f = lambda partition: n**len(partition) elif n == infinity: @@ -825,7 +830,12 @@ def exponential_specialization(self, t=None, q=1): """ if q == 1: if t is None: - t = self.base_ring()["t"].gen() + try: + self.base_ring()('t') + except TypeError: + t = self.base_ring()["t"].gen() + else: + raise ValueError("the variable t is in the base ring, pass it explicitely") def f(partition): n = 0 for part in partition: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 771eafb5ee1..1ef5dcfaca6 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -618,7 +618,12 @@ def principal_specialization(self, n=infinity, q=None): """ if q is None: - q = self.base_ring()["q"].fraction_field().gen() + try: + self.base_ring()('q') + except TypeError: + q = self.base_ring()["q"].gen() + else: + raise ValueError("the variable q is in the base ring, pass it explicitely") if q == 1: f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) / prod(h for h in partition.hooks())) @@ -694,7 +699,12 @@ def exponential_specialization(self, t=None, q=1): """ if q == 1: if t is None: - t = self.base_ring()["t"].gen() + try: + self.base_ring()('t') + except TypeError: + t = self.base_ring()["t"].gen() + else: + raise ValueError("the variable t is in the base ring, pass it explicitely") def f(partition): n = partition.size() return (StandardTableaux(partition).cardinality() diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index cd6e1cad5e9..335e7ecc625 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5476,6 +5476,30 @@ def principal_specialization(self, n=infinity, q=None): sage: (h[3]+h[2]).principal_specialization(q=var("q")) 1/((q^2 - 1)*(q - 1)) - 1/((q^3 - 1)*(q^2 - 1)*(q - 1)) + In case ``q`` is in the base ring, it must be passed explicitely:: + + sage: R = QQ['q,t'] + sage: Ht = SymmetricFunctions(R).macdonald().Ht() + sage: Ht[2].principal_specialization() + Traceback (most recent call last): + ... + ValueError: the variable q is in the base ring, pass it explicitely + + sage: Ht[2].principal_specialization(q=R("q")) + (-q^2 - 1)/(-q^3 + q^2 + q - 1) + + Note that the stable principal specialization can be obtained as a plethysm:: + + sage: R = QQ['q'].fraction_field() + sage: s = SymmetricFunctions(R).s() + sage: one = s.one() + sage: q = R("q") + sage: f = s[3,2,2] + sage: f.principal_specialization(q=q) == f(one/(1-q)).coefficient([]) + True + sage: f.principal_specialization(n=4,q=q) == f(one*(1-q^4)/(1-q)).coefficient([]) + True + TESTS:: sage: m = SymmetricFunctions(QQ).m() From cb893fd1a370b4c776e7480bb4eeb66623c26969 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 4 Dec 2019 22:52:23 +0100 Subject: [PATCH 119/476] explicitely -> explicitly --- src/sage/combinat/sf/elementary.py | 4 ++-- src/sage/combinat/sf/homogeneous.py | 4 ++-- src/sage/combinat/sf/monomial.py | 2 +- src/sage/combinat/sf/powersum.py | 4 ++-- src/sage/combinat/sf/schur.py | 4 ++-- src/sage/combinat/sf/sfa.py | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 6c939b954c3..bbe50025016 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -360,7 +360,7 @@ def principal_specialization(self, n=infinity, q=None): except TypeError: q = self.base_ring()["q"].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitely") + raise ValueError("the variable q is in the base ring, pass it explicitly") if q == 1: f = lambda partition: prod(binomial(n, part) for part in partition) elif n == infinity: @@ -433,7 +433,7 @@ def exponential_specialization(self, t=None, q=1): except TypeError: t = self.base_ring()["t"].gen() else: - raise ValueError("the variable t is in the base ring, pass it explicitely") + raise ValueError("the variable t is in the base ring, pass it explicitly") def f(partition): n = 0 m = 1 diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 2f4f9b9bd08..f240f78aacb 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -273,7 +273,7 @@ def principal_specialization(self, n=infinity, q=None): except TypeError: q = self.base_ring()["q"].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitely") + raise ValueError("the variable q is in the base ring, pass it explicitly") if q == 1: f = lambda partition: prod(binomial(n+part-1, part) for part in partition) elif n == infinity: @@ -352,7 +352,7 @@ def exponential_specialization(self, t=None, q=1): except TypeError: t = self.base_ring()["t"].gen() else: - raise ValueError("the variable t is in the base ring, pass it explicitely") + raise ValueError("the variable t is in the base ring, pass it explicitly") def f(partition): n = 0 m = 1 diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index afa935d53c1..795521d969d 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -427,7 +427,7 @@ def exponential_specialization(self, t=None, q=1): except TypeError: t = self.base_ring()["t"].gen() else: - raise ValueError("the variable t is in the base ring, pass it explicitely") + raise ValueError("the variable t is in the base ring, pass it explicitly") def f(partition): n = 0 for part in partition: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index d72c2ce9b9c..34e440372f1 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -761,7 +761,7 @@ def principal_specialization(self, n=infinity, q=None): except TypeError: q = self.base_ring()["q"].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitely") + raise ValueError("the variable q is in the base ring, pass it explicitly") if q == 1: f = lambda partition: n**len(partition) elif n == infinity: @@ -835,7 +835,7 @@ def exponential_specialization(self, t=None, q=1): except TypeError: t = self.base_ring()["t"].gen() else: - raise ValueError("the variable t is in the base ring, pass it explicitely") + raise ValueError("the variable t is in the base ring, pass it explicitly") def f(partition): n = 0 for part in partition: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 1ef5dcfaca6..52cb1d50ad7 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -623,7 +623,7 @@ def principal_specialization(self, n=infinity, q=None): except TypeError: q = self.base_ring()["q"].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitely") + raise ValueError("the variable q is in the base ring, pass it explicitly") if q == 1: f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) / prod(h for h in partition.hooks())) @@ -704,7 +704,7 @@ def exponential_specialization(self, t=None, q=1): except TypeError: t = self.base_ring()["t"].gen() else: - raise ValueError("the variable t is in the base ring, pass it explicitely") + raise ValueError("the variable t is in the base ring, pass it explicitly") def f(partition): n = partition.size() return (StandardTableaux(partition).cardinality() diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 335e7ecc625..85713fb65b3 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5476,14 +5476,14 @@ def principal_specialization(self, n=infinity, q=None): sage: (h[3]+h[2]).principal_specialization(q=var("q")) 1/((q^2 - 1)*(q - 1)) - 1/((q^3 - 1)*(q^2 - 1)*(q - 1)) - In case ``q`` is in the base ring, it must be passed explicitely:: + In case ``q`` is in the base ring, it must be passed explicitly:: sage: R = QQ['q,t'] sage: Ht = SymmetricFunctions(R).macdonald().Ht() sage: Ht[2].principal_specialization() Traceback (most recent call last): ... - ValueError: the variable q is in the base ring, pass it explicitely + ValueError: the variable q is in the base ring, pass it explicitly sage: Ht[2].principal_specialization(q=R("q")) (-q^2 - 1)/(-q^3 + q^2 + q - 1) From 51f32231c8becc78dec5eb428d3883194981ead2 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Dec 2019 13:50:59 +0100 Subject: [PATCH 120/476] fix default values for eponential specialisation, import q_analogues locally --- src/sage/combinat/sf/elementary.py | 47 ++++++++++++++++++----------- src/sage/combinat/sf/homogeneous.py | 46 +++++++++++++++++----------- src/sage/combinat/sf/monomial.py | 19 +++++++----- src/sage/combinat/sf/powersum.py | 41 +++++++++++++++---------- src/sage/combinat/sf/schur.py | 32 +++++++++++++------- src/sage/combinat/sf/sfa.py | 4 ++- 6 files changed, 120 insertions(+), 69 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index bbe50025016..8073daa5c58 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -23,7 +23,6 @@ from sage.misc.all import prod from sage.functions.other import factorial, binomial from sage.rings.all import infinity -from sage.combinat.q_analogues import q_binomial, q_factorial ################################### # # @@ -354,13 +353,19 @@ def principal_specialization(self, n=infinity, q=None): 0 """ - if q is None: + from sage.combinat.q_analogues import q_binomial + + def get_variable(ring, name): try: - self.base_ring()('q') + ring(name) except TypeError: - q = self.base_ring()["q"].gen() + return ring[name].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitly") + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + + if q is None: + q = get_variable(self.base_ring(), "q") + if q == 1: f = lambda partition: prod(binomial(n, part) for part in partition) elif n == infinity: @@ -408,7 +413,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If + ``q`` is ``None`` create the fraction field of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -426,14 +433,20 @@ def exponential_specialization(self, t=None, q=1): 0 """ + from sage.combinat.q_analogues import q_factorial + + def get_variable(ring, name): + try: + ring(name) + except TypeError: + return ring[name].gen() + else: + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + if q == 1: if t is None: - try: - self.base_ring()('t') - except TypeError: - t = self.base_ring()["t"].gen() - else: - raise ValueError("the variable t is in the base ring, pass it explicitly") + t = get_variable(self.base_ring(), 't') + def f(partition): n = 0 m = 1 @@ -445,13 +458,13 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) if q is None and t is None: - Rq = self.base_ring()["q"].fraction_field() - q = Rq.gen() - t = Rq["t"].gen() + q = get_variable(self.base_ring(), 'q') + t = get_variable(q.parent(), 't') elif q is None: - q = t.parent()["q"].fraction_field().gen() + q = get_variable(t.parent(), 'q') elif t is None: - t = q.parent()["t"].gen() + t = get_variable(q.parent(), 't') + def f(partition): n = 0 diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index f240f78aacb..54b174ffc1a 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -31,7 +31,6 @@ from sage.rings.all import infinity from sage.misc.all import prod from sage.functions.other import factorial, binomial -from sage.combinat.q_analogues import q_binomial, q_factorial class SymmetricFunctionAlgebra_homogeneous(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): @@ -267,13 +266,19 @@ def principal_specialization(self, n=infinity, q=None): 0 """ - if q is None: + from sage.combinat.q_analogues import q_binomial + + def get_variable(ring, name): try: - self.base_ring()('q') + ring(name) except TypeError: - q = self.base_ring()["q"].gen() + return ring[name].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitly") + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + + if q is None: + q = get_variable(self.base_ring(), 'q') + if q == 1: f = lambda partition: prod(binomial(n+part-1, part) for part in partition) elif n == infinity: @@ -318,7 +323,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If + ``q`` is ``None`` create the fraction field of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -345,14 +352,20 @@ def exponential_specialization(self, t=None, q=1): 0 """ + from sage.combinat.q_analogues import q_factorial + + def get_variable(ring, name): + try: + ring(name) + except TypeError: + return ring[name].gen() + else: + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + if q == 1: if t is None: - try: - self.base_ring()('t') - except TypeError: - t = self.base_ring()["t"].gen() - else: - raise ValueError("the variable t is in the base ring, pass it explicitly") + t = get_variable(self.base_ring(), 't') + def f(partition): n = 0 m = 1 @@ -364,13 +377,12 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) if q is None and t is None: - Rq = self.base_ring()["q"].fraction_field() - q = Rq.gen() - t = Rq["t"].gen() + q = get_variable(self.base_ring(), 'q') + t = get_variable(q.parent(), 't') elif q is None: - q = t.parent()["q"].fraction_field().gen() + q = get_variable(t.parent(), 'q') elif t is None: - t = q.parent()["t"].gen() + t = get_variable(q.parent(), 't') def f(partition): n = 0 diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 795521d969d..5d5f205943a 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -397,7 +397,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If + ``q`` is ``None`` create the fraction field of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -420,14 +422,17 @@ def exponential_specialization(self, t=None, q=1): 0 """ + def get_variable(ring, name): + try: + ring(name) + except TypeError: + return ring[name].gen() + else: + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + if q == 1: if t is None: - try: - self.base_ring()('t') - except TypeError: - t = self.base_ring()["t"].gen() - else: - raise ValueError("the variable t is in the base ring, pass it explicitly") + t = get_variable(self.base_ring(), 't') def f(partition): n = 0 for part in partition: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 34e440372f1..d835d9a0d6c 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -755,13 +755,17 @@ def principal_specialization(self, n=infinity, q=None): 0 """ - if q is None: + def get_variable(ring, name): try: - self.base_ring()('q') + ring(name) except TypeError: - q = self.base_ring()["q"].gen() + return ring[name].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitly") + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + + if q is None: + q = get_variable(self.base_ring(), 'q') + if q == 1: f = lambda partition: n**len(partition) elif n == infinity: @@ -805,7 +809,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If + ``q`` is ``None`` create the fraction field of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -828,14 +834,18 @@ def exponential_specialization(self, t=None, q=1): 0 """ + def get_variable(ring, name): + try: + ring(name) + except TypeError: + return ring[name].gen() + else: + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + if q == 1: if t is None: - try: - self.base_ring()('t') - except TypeError: - t = self.base_ring()["t"].gen() - else: - raise ValueError("the variable t is in the base ring, pass it explicitly") + t = get_variable(self.base_ring(), 't') + def f(partition): n = 0 for part in partition: @@ -847,13 +857,12 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) if q is None and t is None: - Rq = self.base_ring()["q"].fraction_field() - q = Rq.gen() - t = Rq["t"].gen() + q = get_variable(self.base_ring(), 'q') + t = get_variable(q.parent(), 't') elif q is None: - q = t.parent()["q"].fraction_field().gen() + q = get_variable(t.parent(), 'q') elif t is None: - t = q.parent()["t"].gen() + t = get_variable(q.parent(), 't') def f(partition): n = 0 diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 52cb1d50ad7..4706e61dee6 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -617,13 +617,17 @@ def principal_specialization(self, n=infinity, q=None): 0 """ - if q is None: + def get_variable(ring, name): try: - self.base_ring()('q') + ring(name) except TypeError: - q = self.base_ring()["q"].gen() + return ring[name].gen() else: - raise ValueError("the variable q is in the base ring, pass it explicitly") + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + + if q is None: + q = get_variable(self.base_ring(), 'q') + if q == 1: f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) / prod(h for h in partition.hooks())) @@ -672,7 +676,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If + ``q`` is ``None`` create the fraction field of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -697,14 +703,18 @@ def exponential_specialization(self, t=None, q=1): 0 """ + def get_variable(ring, name): + try: + ring(name) + except TypeError: + return ring[name].gen() + else: + raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) + if q == 1: if t is None: - try: - self.base_ring()('t') - except TypeError: - t = self.base_ring()["t"].gen() - else: - raise ValueError("the variable t is in the base ring, pass it explicitly") + t = get_variable(self.base_ring(), 't') + def f(partition): n = partition.size() return (StandardTableaux(partition).cardinality() diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 85713fb65b3..4327085ef7d 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5564,7 +5564,9 @@ def exponential_specialization(self, t=None, q=1): is to create the fraction field of polynomials in ``t`` over the coefficient ring. - - ``q`` (default: 1) -- the value to use for `q`. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create the fraction field of polynomials in + ``q`` over the coefficient ring. EXAMPLES:: From 459a4dfd96235d3d8d39fa6539d0022aed0550d2 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Dec 2019 19:33:31 +0100 Subject: [PATCH 121/476] specialisation -> specialization, remove erroneous "stable" --- src/sage/combinat/sf/elementary.py | 4 ++-- src/sage/combinat/sf/homogeneous.py | 4 ++-- src/sage/combinat/sf/monomial.py | 4 ++-- src/sage/combinat/sf/powersum.py | 6 +++--- src/sage/combinat/sf/schur.py | 4 ++-- src/sage/combinat/sf/sfa.py | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 8073daa5c58..9e03c07ad6f 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -403,9 +403,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 54b174ffc1a..b42917b21e1 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -313,9 +313,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 5d5f205943a..4b89f53393d 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -387,9 +387,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index d835d9a0d6c..10c1aa00a3e 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -744,7 +744,7 @@ def principal_specialization(self, n=infinity, q=None): sage: x.principal_specialization(3) 8*q^6 + 18*q^5 + 36*q^4 + 38*q^3 + 36*q^2 + 18*q + 9 - If ``n`` is not given we return the stable principal specialisation:: + If ``n`` is not given we return the stable principal specialization:: sage: x.principal_specialization(q=var("q")) 3/((q^2 - 1)*(q - 1)) - 5/(q - 1)^3 + 1 @@ -799,9 +799,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 4706e61dee6..228c5c22390 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -666,9 +666,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 4327085ef7d..09884c878f4 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5488,7 +5488,7 @@ def principal_specialization(self, n=infinity, q=None): sage: Ht[2].principal_specialization(q=R("q")) (-q^2 - 1)/(-q^3 + q^2 + q - 1) - Note that the stable principal specialization can be obtained as a plethysm:: + Note that the principal specialization can be obtained as a plethysm:: sage: R = QQ['q'].fraction_field() sage: s = SymmetricFunctions(R).s() @@ -5497,7 +5497,7 @@ def principal_specialization(self, n=infinity, q=None): sage: f = s[3,2,2] sage: f.principal_specialization(q=q) == f(one/(1-q)).coefficient([]) True - sage: f.principal_specialization(n=4,q=q) == f(one*(1-q^4)/(1-q)).coefficient([]) + sage: f.principal_specialization(n=4, q=q) == f(one*(1-q^4)/(1-q)).coefficient([]) True TESTS:: @@ -5554,9 +5554,9 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), - where `ps(f)` is the stable principal specialisation of `f`. + where `ps(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal - specialisation is an invalid operation. + specialization is an invalid operation. INPUT: From 8f09ff6db1ca3228546f5ef3509182120e27809c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Dec 2019 22:02:14 +0100 Subject: [PATCH 122/476] documentation improvements --- src/sage/combinat/sf/elementary.py | 23 ++++++++++++----------- src/sage/combinat/sf/homogeneous.py | 23 ++++++++++++----------- src/sage/combinat/sf/monomial.py | 23 ++++++++++++----------- src/sage/combinat/sf/powersum.py | 13 ++++++------- src/sage/combinat/sf/schur.py | 24 ++++++++++++------------ src/sage/combinat/sf/sfa.py | 23 ++++++++++++----------- 6 files changed, 66 insertions(+), 63 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 9e03c07ad6f..df34e018cec 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -328,7 +328,7 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create the fraction field of + the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -389,15 +389,17 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions as .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, .. MATH:: @@ -409,13 +411,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If - ``q`` is ``None`` create the fraction field of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index b42917b21e1..eef2d6b7744 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -246,7 +246,7 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create the fraction field of + the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -299,15 +299,17 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions as .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, .. MATH:: @@ -319,13 +321,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If - ``q`` is ``None`` create the fraction field of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 4b89f53393d..024127e61f5 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -337,7 +337,7 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create the fraction field of + the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -373,15 +373,17 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions as .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, .. MATH:: @@ -393,13 +395,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If - ``q`` is ``None`` create the fraction field of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 10c1aa00a3e..262a0c58ee1 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -725,7 +725,7 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create the fraction field of + the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -805,13 +805,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If - ``q`` is ``None`` create the fraction field of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 228c5c22390..89f673b5aa4 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -594,7 +594,7 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create the fraction field of + the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -652,15 +652,17 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions as .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, .. MATH:: @@ -672,14 +674,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. - - - ``q`` (default: 1) -- the value to use for `q`. If - ``q`` is ``None`` create the fraction field of - polynomials in ``q`` over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. + - ``q`` (default: 1) -- the value to use for `q`. If ``q`` + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 09884c878f4..36ee50f680a 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5459,8 +5459,8 @@ def principal_specialization(self, n=infinity, q=None): specialization. - ``q`` (default: ``None``) -- the value to use for `q`, the - default is to create the fraction field of polynomials in - ``q`` over the coefficient ring. + default is to create a ring (or fraction field) of + polynomials in ``q`` over the coefficient ring. EXAMPLES:: @@ -5540,15 +5540,17 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions as .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, .. MATH:: @@ -5560,13 +5562,12 @@ def exponential_specialization(self, t=None, q=1): INPUT: - - ``t`` (default: None) -- the value to use for `t`, the default - is to create the fraction field of polynomials in ``t`` - over the coefficient ring. + - ``t`` (default: None) -- the value to use for `t`, the + default is to create a ring of polynomials in ``t``. - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create the fraction field of polynomials in - ``q`` over the coefficient ring. + is ``None`` create a ring (or fraction field) of + polynomials in ``q``. EXAMPLES:: From 0a04ac9c9629e047304e9ced848f2bffb93fc111 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 5 Dec 2019 22:07:53 +0100 Subject: [PATCH 123/476] homogeneous is faster than powersum for schur --- src/sage/combinat/sf/schur.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 89f673b5aa4..44d46692e50 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -722,7 +722,10 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) - return self.parent().realization_of().powersum()(self).exponential_specialization(t=t, q=q) + # if self is nice in the schur basis, the homogeneous + # symmetric functions seem to be a faster fallback than + # the powersum symmetric functions + return self.parent().realization_of().homogeneous()(self).exponential_specialization(t=t, q=q) # Backward compatibility for unpickling From 97f2a566a3af9c2653d1b37151eb5ac73ed68e4b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 6 Dec 2019 12:10:34 +0100 Subject: [PATCH 124/476] formulas in documentation, special case exponential specialization for Schur --- src/sage/combinat/sf/elementary.py | 11 +++++- src/sage/combinat/sf/homogeneous.py | 10 +++++ src/sage/combinat/sf/monomial.py | 9 +++++ src/sage/combinat/sf/powersum.py | 10 +++++ src/sage/combinat/sf/schur.py | 57 +++++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index df34e018cec..2a95d78cb44 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -331,6 +331,16 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. + We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + + .. MATH:: + + ps_{n,q}(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} \binom{n}{\lambda_i}_q + + ps_{n,1}(e_\lambda) = \prod_i \binom{n}{\lambda_i} + + ps_q(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} / \prod_{j=1}^{\lambda_i} (1-q^j) + EXAMPLES:: sage: e = SymmetricFunctions(QQ).e() @@ -466,7 +476,6 @@ def f(partition): elif t is None: t = get_variable(q.parent(), 't') - def f(partition): n = 0 m = 1 diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index eef2d6b7744..25128320686 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -249,6 +249,16 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. + We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + + .. MATH:: + + ps_{n,q}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i}_q + + ps_{n,1}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i} + + ps_q(h_\lambda) = 1 / \prod_i \prod_{j=1}^{\lambda_i} (1-q^j) + EXAMPLES:: sage: h = SymmetricFunctions(QQ).h() diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 024127e61f5..5dcdb427263 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -340,6 +340,15 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. + For ``q=1`` we use the formula from Proposition 7.8.3 of [EnumComb2]_ + + .. MATH:: + + ps_{n,1}(m_\lambda) = \binom{n}{len(\lambda)} + \binom{len(\lambda)}{m_1(\lambda), m_2(\lambda),\dots} + + In all other cases, we convert to powersum symmetric functions. + EXAMPLES:: sage: m = SymmetricFunctions(QQ).m() diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 262a0c58ee1..49ae8cb51f3 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -728,6 +728,16 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. + We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + + .. MATH:: + + ps_{n,q}(p_\lambda) = \prod_i (1-q^{n\lambda_i}) / (1-q^{\lambda_i}) + + ps_{n,1}(p_\lambda) = n^{len(\lambda)} + + ps_q(p_\lambda) = 1 / \prod_i (1-q^{\lambda_i}) + EXAMPLES:: sage: p = SymmetricFunctions(QQ).p() diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 44d46692e50..3b20e2712bd 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -597,6 +597,27 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. + For `q=1` we use the formula from Corollary 7.21.4 of [EnumComb2]_ + + .. MATH:: + + ps_{n,1}(s_\lambda) = \prod_{u\in\lambda} (n+c(u)) / h(u), + + where `h(u)` is the hook length of a cell `u` in `\lambda`. + + For `n=infinity` we use the formula from Corollary 7.21.3 of [EnumComb2]_ + + .. MATH:: + + ps_q(s_\lambda) = q^{\sum_i i\lambda_i} / \prod_{u\in\lambda} (1-q^{h(u)}) + + Otherwise, we use the formula from Corollary 7.21.2 of [EnumComb2]_ + + .. MATH:: + + ps_{n,q}(s_\lambda) = q^{\sum_i i\lambda_i} + \prod_{u\in\lambda} (1-q^{n+c(u)}/(1-q^{h(u)}) + EXAMPLES:: sage: s = SymmetricFunctions(QQ).s() @@ -681,6 +702,25 @@ def exponential_specialization(self, t=None, q=1): is ``None`` create a ring (or fraction field) of polynomials in ``q``. + We use the formula in the proof of Corollary 7.21.6 of + [EnumComb2]_ + + .. MATH:: + + ex_{n,q}(s_\lambda) = t^n q^{\sum_i i\lambda_i} + / \prod_{u\in\lambda} (1 + \dots + q^{h(u)-1}) + + where `h(u)` is the hook length of a cell `u` in `\lambda`. + + As a limit case, we obtain a formula for `q=1` + + .. MATH:: + + ex_{n,1}(s_\lambda) = f^\lambda t^n / n! + + where `f^\lambda` is the number of standard Young + tableaux of shape `\lambda`. + EXAMPLES:: sage: s = SymmetricFunctions(QQ).s() @@ -722,10 +762,19 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) - # if self is nice in the schur basis, the homogeneous - # symmetric functions seem to be a faster fallback than - # the powersum symmetric functions - return self.parent().realization_of().homogeneous()(self).exponential_specialization(t=t, q=q) + if q is None and t is None: + q = get_variable(self.base_ring(), 'q') + t = get_variable(q.parent(), 't') + elif q is None: + q = get_variable(t.parent(), 'q') + elif t is None: + t = get_variable(q.parent(), 't') + + f = lambda partition: (t**partition.size() + * q**sum(i*part for i, part in enumerate(partition)) + / prod(sum(q**i for i in range(h)) for h in partition.hooks())) + + return self.parent()._apply_module_morphism(self, f, t.parent()) # Backward compatibility for unpickling From 13fc77dc801762c367a761c6b9fab3415ea874b4 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 26 Dec 2019 12:03:33 -0500 Subject: [PATCH 125/476] minor changes to documentation, mainly punctuation --- src/sage/combinat/sf/elementary.py | 12 ++++++------ src/sage/combinat/sf/homogeneous.py | 12 ++++++------ src/sage/combinat/sf/monomial.py | 9 +++++---- src/sage/combinat/sf/powersum.py | 13 ++++++------- src/sage/combinat/sf/schur.py | 10 +++++----- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 2a95d78cb44..7a58a7852ea 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -331,15 +331,15 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + We use the formulas from Proposition 7.8.3 of [EnumComb2]_, .. MATH:: - ps_{n,q}(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} \binom{n}{\lambda_i}_q + ps_{n,q}(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} \binom{n}{\lambda_i}_q, - ps_{n,1}(e_\lambda) = \prod_i \binom{n}{\lambda_i} + ps_{n,1}(e_\lambda) = \prod_i \binom{n}{\lambda_i}, - ps_q(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} / \prod_{j=1}^{\lambda_i} (1-q^j) + ps_q(e_\lambda) = \prod_i q^{\binom{\lambda_i}{2}} / \prod_{j=1}^{\lambda_i} (1-q^j). EXAMPLES:: @@ -413,9 +413,9 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal specialization is an invalid operation. diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 25128320686..a1190a316fa 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -249,15 +249,15 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + We use the formulas from Proposition 7.8.3 of [EnumComb2]_, .. MATH:: - ps_{n,q}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i}_q + ps_{n,q}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i}_q, - ps_{n,1}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i} + ps_{n,1}(h_\lambda) = \prod_i \binom{n+\lambda_i-1}{\lambda_i}, - ps_q(h_\lambda) = 1 / \prod_i \prod_{j=1}^{\lambda_i} (1-q^j) + ps_q(h_\lambda) = 1 / \prod_i \prod_{j=1}^{\lambda_i} (1-q^j). EXAMPLES:: @@ -323,9 +323,9 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal specialization is an invalid operation. diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 5dcdb427263..652a32ce82e 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -340,12 +340,13 @@ def principal_specialization(self, n=infinity, q=None): the default is to create a ring (or fraction field) of polynomials in ``q`` over the coefficient ring. - For ``q=1`` we use the formula from Proposition 7.8.3 of [EnumComb2]_ + For ``q=1`` and finite ``n`` we use the formula from + Proposition 7.8.3 of [EnumComb2]_, .. MATH:: ps_{n,1}(m_\lambda) = \binom{n}{len(\lambda)} - \binom{len(\lambda)}{m_1(\lambda), m_2(\lambda),\dots} + \binom{len(\lambda)}{m_2(\lambda), m_2(\lambda),\dots}. In all other cases, we convert to powersum symmetric functions. @@ -396,9 +397,9 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal specialization is an invalid operation. diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 49ae8cb51f3..60714c436e9 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -732,11 +732,11 @@ def principal_specialization(self, n=infinity, q=None): .. MATH:: - ps_{n,q}(p_\lambda) = \prod_i (1-q^{n\lambda_i}) / (1-q^{\lambda_i}) + ps_{n,q}(p_\lambda) = \prod_i (1-q^{n\lambda_i}) / (1-q^{\lambda_i}), - ps_{n,1}(p_\lambda) = n^{len(\lambda)} + ps_{n,1}(p_\lambda) = n^{len(\lambda)}, - ps_q(p_\lambda) = 1 / \prod_i (1-q^{\lambda_i}) + ps_q(p_\lambda) = 1 / \prod_i (1-q^{\lambda_i}). EXAMPLES:: @@ -796,8 +796,7 @@ def exponential_specialization(self, t=None, q=1): = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` - as + defined on homogeneous symmetric functions `f` of degree `n` as .. MATH:: @@ -807,9 +806,9 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal specialization is an invalid operation. diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 3b20e2712bd..c8181a2615e 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -609,14 +609,14 @@ def principal_specialization(self, n=infinity, q=None): .. MATH:: - ps_q(s_\lambda) = q^{\sum_i i\lambda_i} / \prod_{u\in\lambda} (1-q^{h(u)}) + ps_q(s_\lambda) = q^{\sum_i i\lambda_i} / \prod_{u\in\lambda} (1-q^{h(u)}). - Otherwise, we use the formula from Corollary 7.21.2 of [EnumComb2]_ + Otherwise, we use the formula from Corollary 7.21.2 of [EnumComb2]_, .. MATH:: ps_{n,q}(s_\lambda) = q^{\sum_i i\lambda_i} - \prod_{u\in\lambda} (1-q^{n+c(u)}/(1-q^{h(u)}) + \prod_{u\in\lambda} (1-q^{n+c(u)}/(1-q^{h(u)}). EXAMPLES:: @@ -687,9 +687,9 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f`. Note that setting `q = 1` in the stable principal specialization is an invalid operation. From 90e1e0f67c3cd233fcfaa344012953d648fd0bb9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 1 Jan 2020 15:46:28 +0100 Subject: [PATCH 126/476] move q=1, stable comment from exponential specialization to principal specialization and raise appropriate error --- src/sage/combinat/sf/elementary.py | 6 ++++-- src/sage/combinat/sf/homogeneous.py | 6 ++++-- src/sage/combinat/sf/monomial.py | 2 ++ src/sage/combinat/sf/powersum.py | 9 ++++++--- src/sage/combinat/sf/schur.py | 7 ++++--- src/sage/combinat/sf/sfa.py | 22 +++++++++++++++++++--- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 7a58a7852ea..f2d84af5104 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -319,6 +319,8 @@ def principal_specialization(self, n=infinity, q=None): The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. + Note that setting `q = 1` in the stable principal + specialization is an invalid operation. INPUT: @@ -377,6 +379,8 @@ def get_variable(ring, name): q = get_variable(self.base_ring(), "q") if q == 1: + if n == infinity: + raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: prod(binomial(n, part) for part in partition) elif n == infinity: f = lambda partition: prod(q**binomial(part, 2)/prod((1-q**i) @@ -416,8 +420,6 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps_q(f), where `ps_q(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index a1190a316fa..117081dbb68 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -237,6 +237,8 @@ def principal_specialization(self, n=infinity, q=None): The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. + Note that setting `q = 1` in the stable principal + specialization is an invalid operation. INPUT: @@ -290,6 +292,8 @@ def get_variable(ring, name): q = get_variable(self.base_ring(), 'q') if q == 1: + if n == infinity: + raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: prod(binomial(n+part-1, part) for part in partition) elif n == infinity: f = lambda partition: prod(1/prod((1-q**i) for i in range(1, part+1)) for part in partition) @@ -326,8 +330,6 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps_q(f), where `ps_q(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 652a32ce82e..7b11cc79e5d 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -368,6 +368,8 @@ def principal_specialization(self, n=infinity, q=None): """ if q == 1: + if n == infinity: + raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) return self.parent()._apply_module_morphism(self, f, q.parent()) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 60714c436e9..b0360044f35 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -707,7 +707,8 @@ def eval_at_permutation_roots(self, rho): return p._apply_module_morphism(self, on_basis, R) def principal_specialization(self, n=infinity, q=None): - r"""Return the principal specialization of the symmetric function. + r""" + Return the principal specialization of the symmetric function. The principal specialization of order `n` is the ring homomorphism given by setting `x_i = q^i` for `i \in @@ -716,6 +717,8 @@ def principal_specialization(self, n=infinity, q=None): The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. + Note that setting `q = 1` in the stable principal + specialization is an invalid operation. INPUT: @@ -777,6 +780,8 @@ def get_variable(ring, name): q = get_variable(self.base_ring(), 'q') if q == 1: + if n == infinity: + raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: n**len(partition) elif n == infinity: f = lambda partition: prod(1/(1-q**part) for part in partition) @@ -809,8 +814,6 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps_q(f), where `ps_q(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index c8181a2615e..19b7e972344 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -585,6 +585,8 @@ def principal_specialization(self, n=infinity, q=None): The stable principal specialization is the ring homomorphism given by setting `x_i = q^i` for all `i`. + Note that setting `q = 1` in the stable principal + specialization is an invalid operation. INPUT: @@ -648,8 +650,9 @@ def get_variable(ring, name): if q is None: q = get_variable(self.base_ring(), 'q') - if q == 1: + if n == infinity: + raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) / prod(h for h in partition.hooks())) elif n == infinity: @@ -690,8 +693,6 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps_q(f), where `ps_q(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. INPUT: diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 36ee50f680a..e4bb2cb59d3 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5449,7 +5449,9 @@ def principal_specialization(self, n=infinity, q=None): of [EnumComb2]_. The stable principal specialization is the ring homomorphism - given by setting `x_i = q^i` for all `i`. + given by setting `x_i = q^i` for all `i`. Note that setting + `q = 1` in the stable principal specialization is an invalid + operation. INPUT: @@ -5526,6 +5528,22 @@ def principal_specialization(self, n=infinity, q=None): sage: len(set([b(x).principal_specialization(n=4, q=2) for b in B])) 1 + Check that the stable principal specialization at `q = 1` + raises a ``ValueError``: + + sage: def test_error(x): + ....: message = "the stable principal specialization of %s at q=1 should raise a ValueError" + ....: try: + ....: x.principal_specialization(q=1) + ....: except ValueError as e: + ....: return(e) + ....: except StandardError as e: + ....: raise ValueError((message + ", but raised '%s' instead") % (x, e)) + ....: raise ValueError((message + ", but didn't") % x) + + sage: set([str(test_error(b(x))) for b in B]) + {'the stable principal specialization at q=1 is not defined'} + """ p = self.parent().realization_of().powersum() return p(self).principal_specialization(n, q=q) @@ -5557,8 +5575,6 @@ def exponential_specialization(self, t=None, q=1): ex_q(f) = (1-q)^n t^n ps(f), where `ps(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. INPUT: From c6dac5aa0cf3d8ac6ae9302ce0b7f034f02ec1d1 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 2 Apr 2020 15:48:12 +0200 Subject: [PATCH 127/476] improvements to doc To my knowledge, the variables start at x_1, not x_0. --- src/sage/combinat/sf/elementary.py | 30 ++++++++++++++++------------- src/sage/combinat/sf/homogeneous.py | 30 ++++++++++++++++------------- src/sage/combinat/sf/monomial.py | 28 ++++++++++++++++----------- src/sage/combinat/sf/powersum.py | 30 ++++++++++++++++------------- src/sage/combinat/sf/schur.py | 30 ++++++++++++++++------------- src/sage/combinat/sf/sfa.py | 28 +++++++++++++++------------ 6 files changed, 101 insertions(+), 75 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index f2d84af5104..480a2ee3ce0 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -310,17 +310,20 @@ def expand(self, n, alphabet='x'): def principal_specialization(self, n=infinity, q=None): r""" - Return the principal specialization of the symmetric function. + Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section - 7.8 of [EnumComb2]_. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. - The stable principal specialization is the ring - homomorphism given by setting `x_i = q^i` for all `i`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -329,11 +332,12 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_, + We use the formulas from Proposition 7.8.3 of [EnumComb2]_: .. MATH:: diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 117081dbb68..feff79738eb 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -228,17 +228,20 @@ def expand(self, n, alphabet='x'): def principal_specialization(self, n=infinity, q=None): r""" - Return the principal specialization of the symmetric function. + Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section - 7.8 of [EnumComb2]_. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. - The stable principal specialization is the ring - homomorphism given by setting `x_i = q^i` for all `i`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -247,11 +250,12 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_, + We use the formulas from Proposition 7.8.3 of [EnumComb2]_: .. MATH:: diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 7b11cc79e5d..c2bef88a58f 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -319,15 +319,20 @@ def condition(part): ======= def principal_specialization(self, n=infinity, q=None): r""" - Return the principal specialization of the symmetric function. + Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section - 7.8 of [EnumComb2]_. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. - The stable principal specialization is the ring - homomorphism given by setting `x_i = q^i` for all `i`. + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -336,12 +341,13 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. For ``q=1`` and finite ``n`` we use the formula from - Proposition 7.8.3 of [EnumComb2]_, + Proposition 7.8.3 of [EnumComb2]_: .. MATH:: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index b0360044f35..dd70cf22233 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -708,17 +708,20 @@ def eval_at_permutation_roots(self, rho): def principal_specialization(self, n=infinity, q=None): r""" - Return the principal specialization of the symmetric function. + Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section - 7.8 of [EnumComb2]_. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. - The stable principal specialization is the ring - homomorphism given by setting `x_i = q^i` for all `i`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -727,11 +730,12 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + We use the formulas from Proposition 7.8.3 of [EnumComb2]_: .. MATH:: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 19b7e972344..8999f3920ea 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -576,17 +576,20 @@ def expand(self, n, alphabet='x'): def principal_specialization(self, n=infinity, q=None): r""" - Return the principal specialization of the symmetric function. + Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section - 7.8 of [EnumComb2]_. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. - The stable principal specialization is the ring - homomorphism given by setting `x_i = q^i` for all `i`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -595,11 +598,12 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, - the default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. - For `q=1` we use the formula from Corollary 7.21.4 of [EnumComb2]_ + For `q=1` we use the formula from Corollary 7.21.4 of [EnumComb2]_: .. MATH:: diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index e4bb2cb59d3..82445468639 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5443,15 +5443,18 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The principal specialization of order `n` is the ring - homomorphism given by setting `x_i = q^i` for `i \in - \{0,\dots,n-1\}` and `x_i = 0` for `i\geq n`, see Section 7.8 - of [EnumComb2]_. - - The stable principal specialization is the ring homomorphism - given by setting `x_i = q^i` for all `i`. Note that setting - `q = 1` in the stable principal specialization is an invalid - operation. + The *principal specialization* of order `n` is the ring + homomorphism from the ring of symmetric functions to another + commutative ring `R` given by `x_i \mapsto q^{i-1}` for + `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`. + See Section 7.8 of [EnumComb2]_. + + The *stable principal specialization* is the ring + homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + This is well-defined only if the resulting infinite sums + converge; thus, in particular, setting `q = 1` in the + stable principal specialization is an invalid operation. INPUT: @@ -5460,9 +5463,10 @@ def principal_specialization(self, n=infinity, q=None): specialization of order ``n`` or the stable principal specialization. - - ``q`` (default: ``None``) -- the value to use for `q`, the - default is to create a ring (or fraction field) of - polynomials in ``q`` over the coefficient ring. + - ``q`` (default: ``None``) -- the value to use for `q`; the + default is to create a ring of polynomials in ``q`` + (or a field of rational functions in ``q``) over the + given coefficient ring. EXAMPLES:: From 77af27c91a3fd5e773c099fc61222a7ff2258001 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 2 Apr 2020 15:49:56 +0200 Subject: [PATCH 128/476] redirect through monomial, not powersum Powersum conversion only works in char 0 --- src/sage/combinat/sf/sfa.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 82445468639..f6e4004f12b 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5549,8 +5549,8 @@ def principal_specialization(self, n=infinity, q=None): {'the stable principal specialization at q=1 is not defined'} """ - p = self.parent().realization_of().powersum() - return p(self).principal_specialization(n, q=q) + m = self.parent().realization_of().monomial() + return m(self).principal_specialization(n, q=q) def exponential_specialization(self, t=None, q=1): r""" From b2ad980cb9767f150c968f534c16a5b9f2ba1636 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 2 Apr 2020 16:00:52 +0200 Subject: [PATCH 129/476] more doc --- src/sage/combinat/sf/elementary.py | 13 ++++++++++--- src/sage/combinat/sf/homogeneous.py | 2 ++ src/sage/combinat/sf/monomial.py | 2 ++ src/sage/combinat/sf/powersum.py | 7 +++++-- src/sage/combinat/sf/schur.py | 2 ++ src/sage/combinat/sf/sfa.py | 4 +++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 480a2ee3ce0..05b68448ac4 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -317,6 +317,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring @@ -403,9 +405,14 @@ def exponential_specialization(self, t=None, q=1): The exponential specialization `ex` is the ring homomorphism defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. + setting `p_1 = t` and `p_n = 0` for `n > 1`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) + Equivalently, on the basis of homogeneous functions it is + given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of + [EnumComb2]_. + In order for `ex` to be well-defined, the base ring must + be a `\QQ`-algebra. By analogy, the `q`-exponential specialization is a ring homomorphism defined on the complete homogeneous symmetric diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index feff79738eb..40bc4937281 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -235,6 +235,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index c2bef88a58f..a324b568bd9 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -326,6 +326,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index dd70cf22233..59d341ab7c0 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -715,6 +715,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring @@ -804,8 +806,9 @@ def exponential_specialization(self, t=None, q=1): on the basis of homogeneous functions it is given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - By analogy `q`-exponential specialization is a ring homomorphism - defined on homogeneous symmetric functions `f` of degree `n` as + By analogy, the `q`-exponential specialization is a ring + homomorphism defined on the complete homogeneous symmetric + functions `f` by .. MATH:: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 8999f3920ea..c011010a522 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -583,6 +583,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index f6e4004f12b..ecf04060f09 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5448,6 +5448,8 @@ def principal_specialization(self, n=infinity, q=None): commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`. + (To be more precise, it is a `K`-algebra homomorphism, + where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* is the ring @@ -5564,7 +5566,7 @@ def exponential_specialization(self, t=None, q=1): By analogy, the `q`-exponential specialization is a ring homomorphism defined on the complete homogeneous symmetric - functions as + functions by .. MATH:: From 4f5e2c536fd94ae0a08f881740efcd7a94325fdb Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sat, 4 Apr 2020 11:20:50 -0400 Subject: [PATCH 130/476] correct use of n in exponential_specialization documentation in schur.py --- src/sage/combinat/sf/schur.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index c011010a522..ea4b0cd1246 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -714,7 +714,7 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_{n,q}(s_\lambda) = t^n q^{\sum_i i\lambda_i} + ex_{q}(s_\lambda) = t^{|\lambda|} q^{\sum_i i\lambda_i} / \prod_{u\in\lambda} (1 + \dots + q^{h(u)-1}) where `h(u)` is the hook length of a cell `u` in `\lambda`. @@ -723,7 +723,7 @@ def exponential_specialization(self, t=None, q=1): .. MATH:: - ex_{n,1}(s_\lambda) = f^\lambda t^n / n! + ex_{1}(s_\lambda) = f^\lambda t^{|\lambda|} / |\lambda|! where `f^\lambda` is the number of standard Young tableaux of shape `\lambda`. From 3cb3a5f824f038da265a253c6ef36e03bd02b994 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 24 Apr 2020 13:40:11 +0200 Subject: [PATCH 131/476] better behaviour with respect to removable singularities --- src/sage/combinat/sf/powersum.py | 9 ++++++++- src/sage/combinat/sf/schur.py | 17 ++++++++++++++--- src/sage/combinat/sf/sfa.py | 22 +++++++++++++++++----- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 59d341ab7c0..ca0f15d94d2 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -22,6 +22,7 @@ from sage.combinat.partition import Partition from sage.arith.all import divisors from sage.rings.all import infinity +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.all import prod class SymmetricFunctionAlgebra_power(multiplicative.SymmetricFunctionAlgebra_multiplicative): @@ -792,7 +793,13 @@ def get_variable(ring, name): elif n == infinity: f = lambda partition: prod(1/(1-q**part) for part in partition) else: - f = lambda partition: prod((1-q**(n*part))/(1-q**part) for part in partition) + q_lim = PolynomialRing(self.base_ring(), "q").gen() + def f(partition): + denom = prod((1-q**part) for part in partition) + if denom: + return prod((1-q**(n*part)) for part in partition)/denom + quotient = prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition) + return quotient.subs({q_lim: q}) return self.parent()._apply_module_morphism(self, f, q.parent()) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index ea4b0cd1246..02334fcda33 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -23,6 +23,7 @@ import sage.libs.lrcalc.lrcalc as lrcalc from sage.misc.all import prod from sage.rings.infinity import infinity +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.functions.other import factorial from sage.combinat.tableau import StandardTableaux @@ -665,9 +666,19 @@ def get_variable(ring, name): f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) / prod(1-q**h for h in partition.hooks())) else: - f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) - * prod(1-q**(n + partition.content(*c)) for c in partition.cells()) - / prod(1-q**h for h in partition.hooks())) + q_lim = PolynomialRing(self.base_ring(), "q").gen() + def f(partition): + power = q**sum(i*part for i, part in enumerate(partition)) + denom = prod(1-q**h for h in partition.hooks()) + if denom: + return (power + * prod(1-q**(n + partition.content(*c)) + for c in partition.cells()) + / denom) + quotient = (prod(1-q_lim**(n + partition.content(*c)) + for c in partition.cells()) + / prod(1-q_lim**h for h in partition.hooks())) + return (power * quotient.subs({q_lim: q})) return self.parent()._apply_module_morphism(self, f, q.parent()) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index ecf04060f09..86612b510c7 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5494,7 +5494,7 @@ def principal_specialization(self, n=infinity, q=None): ValueError: the variable q is in the base ring, pass it explicitly sage: Ht[2].principal_specialization(q=R("q")) - (-q^2 - 1)/(-q^3 + q^2 + q - 1) + (q^2 + 1)/(q^3 - q^2 - q + 1) Note that the principal specialization can be obtained as a plethysm:: @@ -5550,9 +5550,19 @@ def principal_specialization(self, n=infinity, q=None): sage: set([str(test_error(b(x))) for b in B]) {'the stable principal specialization at q=1 is not defined'} + Check that specifying `q` which is a removable singularity works:: + + sage: S = SymmetricFunctions(QQ) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: m = S.m(); x = m[2,2,1] + sage: set([b(x).principal_specialization(n=4, q=QQbar.zeta(3)) for b in B]) + {-3} + """ - m = self.parent().realization_of().monomial() - return m(self).principal_specialization(n, q=q) + # heuristically, it seems fastest to fall back to the + # elementary basis instead of the powersum basis + e = self.parent().realization_of().elementary() + return e(self).principal_specialization(n, q=q) def exponential_specialization(self, t=None, q=1): r""" @@ -5629,8 +5639,10 @@ def exponential_specialization(self, t=None, q=1): 1 """ - p = self.parent().realization_of().powersum() - return p(self).exponential_specialization(t=t, q=q) + # heuristically, it seems fastest to fall back to the + # elementary basis instead of the powersum basis + e = self.parent().realization_of().elementary() + return e(self).exponential_specialization(t=t, q=q) SymmetricFunctionAlgebra_generic.Element = SymmetricFunctionAlgebra_generic_Element From 2b301b50c0e45fc1db972c17339cb82fd84e8306 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 14:46:22 +0200 Subject: [PATCH 132/476] review the doc --- src/sage/combinat/sf/elementary.py | 74 +++++++++++++++----------- src/sage/combinat/sf/homogeneous.py | 71 +++++++++++++++---------- src/sage/combinat/sf/monomial.py | 76 ++++++++++++++++----------- src/sage/combinat/sf/powersum.py | 77 +++++++++++++++++---------- src/sage/combinat/sf/schur.py | 80 ++++++++++++++++++----------- src/sage/combinat/sf/sfa.py | 76 +++++++++++++++++---------- 6 files changed, 285 insertions(+), 169 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 05b68448ac4..4597f6ea6e5 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -312,17 +312,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -339,7 +344,8 @@ def principal_specialization(self, n=infinity, q=None): (or a field of rational functions in ``q``) over the given coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_: + We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + (using Gaussian binomial coefficients `\binom{u}{v}_q`): .. MATH:: @@ -359,7 +365,7 @@ def principal_specialization(self, n=infinity, q=None): sage: x.principal_specialization(3) 5*q^6 + 18*q^5 + 36*q^4 + 44*q^3 + 36*q^2 + 18*q + 6 - By default, we return a rational functions in q. Sometimes it is + By default, we return a rational functions in `q`. Sometimes it is better to obtain an element of the symbolic ring:: sage: x.principal_specialization(q=var("q")) @@ -403,20 +409,26 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) - Equivalently, on the basis of homogeneous functions it is - given by `ex(h_n) = t^n / n!`, see Proposition 7.8.4 of + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of [EnumComb2]_. - In order for `ex` to be well-defined, the base ring must - be a `\QQ`-algebra. - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions as + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: @@ -424,22 +436,24 @@ def exponential_specialization(self, t=None, q=1): where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` and a homogeneous symmetric function `f` of - degree `n`, + degree `n`, we have .. MATH:: ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps_q(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. EXAMPLES:: diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 40bc4937281..4e932fbc94a 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -230,17 +230,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -257,7 +262,8 @@ def principal_specialization(self, n=infinity, q=None): (or a field of rational functions in ``q``) over the given coefficient ring. - We use the formulas from Proposition 7.8.3 of [EnumComb2]_: + We use the formulas from Proposition 7.8.3 of [EnumComb2]_ + (using Gaussian binomial coefficients `\binom{u}{v}_q`): .. MATH:: @@ -313,15 +319,26 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions as + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of + [EnumComb2]_. + + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: @@ -329,22 +346,24 @@ def exponential_specialization(self, t=None, q=1): where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` and a homogeneous symmetric function `f` of - degree `n`, + degree `n`, we have .. MATH:: ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps_q(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. EXAMPLES:: diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index a324b568bd9..f6c7e2d60ef 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -321,17 +321,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -353,8 +358,10 @@ def principal_specialization(self, n=infinity, q=None): .. MATH:: - ps_{n,1}(m_\lambda) = \binom{n}{len(\lambda)} - \binom{len(\lambda)}{m_2(\lambda), m_2(\lambda),\dots}. + ps_{n,1}(m_\lambda) = \binom{n}{\ell(\lambda)} + \binom{\ell(\lambda)}{m_1(\lambda), m_2(\lambda),\dots}, + + where `\ell(\lambda)` denotes the length of `\lambda`. In all other cases, we convert to powersum symmetric functions. @@ -387,15 +394,26 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions as + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of + [EnumComb2]_. + + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: @@ -403,24 +421,24 @@ def exponential_specialization(self, t=None, q=1): where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` and a homogeneous symmetric function `f` of - degree `n`, + degree `n`, we have .. MATH:: ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps_q(f)` is the stable principal specialization of `f`. - Note that setting `q = 1` in the stable principal - specialization is an invalid operation. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. EXAMPLES:: diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index ca0f15d94d2..ba0399a1566 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -711,17 +711,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -744,9 +749,12 @@ def principal_specialization(self, n=infinity, q=None): ps_{n,q}(p_\lambda) = \prod_i (1-q^{n\lambda_i}) / (1-q^{\lambda_i}), - ps_{n,1}(p_\lambda) = n^{len(\lambda)}, + ps_{n,1}(p_\lambda) = n^{\ell(\lambda)}, - ps_q(p_\lambda) = 1 / \prod_i (1-q^{\lambda_i}). + ps_q(p_\lambda) = 1 / \prod_i (1-q^{\lambda_i}), + + where `\ell(\lambda)` denotes the length of `\lambda`, + and where the products range from `i=1` to `i=\ell(\lambda)`. EXAMPLES:: @@ -807,36 +815,51 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions `f` by + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of + [EnumComb2]_. + + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: ex_q(h_n) = t^n / [n]_q!, - where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` + where `[n]_q!` is the `q`-factorial. Equivalently, for + `q \neq 1` and a homogeneous symmetric function `f` of + degree `n`, we have .. MATH:: ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps_q(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. EXAMPLES:: diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 02334fcda33..5421005f0d1 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -579,17 +579,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -618,14 +623,14 @@ def principal_specialization(self, n=infinity, q=None): .. MATH:: - ps_q(s_\lambda) = q^{\sum_i i\lambda_i} / \prod_{u\in\lambda} (1-q^{h(u)}). + ps_q(s_\lambda) = q^{\sum_i (i-1)\lambda_i} / \prod_{u\in\lambda} (1-q^{h(u)}). - Otherwise, we use the formula from Corollary 7.21.2 of [EnumComb2]_, + Otherwise, we use the formula from Theorem 7.21.2 of [EnumComb2]_, .. MATH:: - ps_{n,q}(s_\lambda) = q^{\sum_i i\lambda_i} - \prod_{u\in\lambda} (1-q^{n+c(u)}/(1-q^{h(u)}). + ps_{n,q}(s_\lambda) = q^{\sum_i (i-1)\lambda_i} + \prod_{u\in\lambda} (1-q^{n+c(u)})/(1-q^{h(u)}). EXAMPLES:: @@ -687,15 +692,26 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions as + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of + [EnumComb2]_. + + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: @@ -703,30 +719,32 @@ def exponential_specialization(self, t=None, q=1): where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` and a homogeneous symmetric function `f` of - degree `n`, + degree `n`, we have .. MATH:: ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps_q(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. We use the formula in the proof of Corollary 7.21.6 of [EnumComb2]_ .. MATH:: - ex_{q}(s_\lambda) = t^{|\lambda|} q^{\sum_i i\lambda_i} - / \prod_{u\in\lambda} (1 + \dots + q^{h(u)-1}) + ex_{q}(s_\lambda) = t^{|\lambda|} q^{\sum_i (i-1)\lambda_i} + / \prod_{u\in\lambda} (1 + q + q^2 + \dots + q^{h(u)-1}) where `h(u)` is the hook length of a cell `u` in `\lambda`. diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 86612b510c7..feb9828a850 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5443,17 +5443,22 @@ def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. - The *principal specialization* of order `n` is the ring - homomorphism from the ring of symmetric functions to another - commutative ring `R` given by `x_i \mapsto q^{i-1}` for - `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. - Here, `q` is a given element of `R`. - (To be more precise, it is a `K`-algebra homomorphism, - where `K` is the base ring.) + The *principal specialization* of order `n` at `q` + is the ring homomorphism `ps_{n,q}` from the ring of + symmetric functions to another commutative ring `R` + given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` + and `x_i \mapsto 0` for `i > n`. + Here, `q` is a given element of `R`, and we assume that + the variables of our symmetric functions are + `x_1, x_2, x_3, \ldots`. + (To be more precise, `ps_{n,q}` is a `K`-algebra + homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. - The *stable principal specialization* is the ring - homomorphism given by `x_i \mapsto q^{i-1}` for all `i`. + The *stable principal specialization* at `q` is the ring + homomorphism `ps_q` from the ring of symmetric functions + to another commutative ring `R` given by + `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. @@ -5558,6 +5563,12 @@ def principal_specialization(self, n=infinity, q=None): sage: set([b(x).principal_specialization(n=4, q=QQbar.zeta(3)) for b in B]) {-3} + sage: S = SymmetricFunctions(GF(3)) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: m = S.m(); x = m[3,2,1] + sage: set([b(x).principal_specialization(n=4, q=GF(3)(2)) for b in B]) + {-3} # Please replace by correct answer + """ # heuristically, it seems fastest to fall back to the # elementary basis instead of the powersum basis @@ -5568,15 +5579,26 @@ def exponential_specialization(self, t=None, q=1): r""" Return the exponential specialization of a symmetric function. - The exponential specialization `ex` is the ring homomorphism - defined on the basis of powersum symmetric functions by - setting `p_1 = t` and `p_n = 0` for `n > 1`. Equivalently, - on the basis of homogeneous functions it is given by `ex(h_n) - = t^n / n!`, see Proposition 7.8.4 of [EnumComb2]_. - - By analogy, the `q`-exponential specialization is a ring - homomorphism defined on the complete homogeneous symmetric - functions by + The *exponential specialization* `ex` at `t` is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R`. + It is defined whenever the base ring `K` is a + `\QQ`-algebra and `t` is an element of `R`. + The easiest way to define it is by specifying its + values on the powersum symmetric functions to be + `p_1 = t` and `p_n = 0` for `n > 1`. + Equivalently, on the homogeneous functions it is + given by `ex(h_n) = t^n / n!`; see Proposition 7.8.4 of + [EnumComb2]_. + + By analogy, the `q`-exponential specialization is a + `K`-algebra homomorphism from the `K`-algebra of + symmetric functions to another `K`-algebra `R` that + depends on two elements `t` and `q` of `R` for which + the elements `1 - q^i` for all positive integers `i` + are invertible. + It can be defined by specifying its values on the + complete homogeneous symmetric functions to be .. MATH:: @@ -5584,22 +5606,24 @@ def exponential_specialization(self, t=None, q=1): where `[n]_q!` is the `q`-factorial. Equivalently, for `q \neq 1` and a homogeneous symmetric function `f` of - degree `n`, + degree `n`, we have .. MATH:: - ex_q(f) = (1-q)^n t^n ps(f), + ex_q(f) = (1-q)^n t^n ps_q(f), - where `ps(f)` is the stable principal specialization of `f`. + where `ps_q(f)` is the stable principal specialization of `f` + (see :meth:`principal_specialization`). + (See (7.29) in [EnumComb2]_.) INPUT: - - ``t`` (default: None) -- the value to use for `t`, the - default is to create a ring of polynomials in ``t``. + - ``t`` (default: ``None``) -- the value to use for `t`; + the default is to create a ring of polynomials in ``t``. - - ``q`` (default: 1) -- the value to use for `q`. If ``q`` - is ``None`` create a ring (or fraction field) of - polynomials in ``q``. + - ``q`` (default: `1`) -- the value to use for `q`. If + ``q`` is ``None``, then a ring (or fraction field) of + polynomials in ``q`` is created. EXAMPLES:: From 2b2d77a11fd4c1ec4b71894c713cb5092290aac5 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 14:48:11 +0200 Subject: [PATCH 133/476] use h, not p, as the base ring might not have 1/n --- src/sage/combinat/sf/monomial.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index f6c7e2d60ef..74fc3e856d3 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -363,7 +363,8 @@ def principal_specialization(self, n=infinity, q=None): where `\ell(\lambda)` denotes the length of `\lambda`. - In all other cases, we convert to powersum symmetric functions. + In all other cases, we convert to complete homogeneous + symmetric functions. EXAMPLES:: @@ -388,7 +389,7 @@ def principal_specialization(self, n=infinity, q=None): f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) return self.parent()._apply_module_morphism(self, f, q.parent()) - return self.parent().realization_of().powersum()(self).principal_specialization(n=n, q=q) + return self.parent().realization_of().homogeneous()(self).principal_specialization(n=n, q=q) def exponential_specialization(self, t=None, q=1): r""" From fc793413912ce162303427b0de0939ce2134fe6f Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 15:46:05 +0200 Subject: [PATCH 134/476] some doctests for a start --- src/sage/combinat/sf/elementary.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 4597f6ea6e5..3c38c476de7 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -376,6 +376,28 @@ def principal_specialization(self, n=infinity, q=None): sage: e.zero().principal_specialization(3) 0 + sage: e = SymmetricFunctions(GF(3)).e() + sage: a = e[2,1].principal_specialization(n=2, q=GF(3)(2)); a + 0 + sage: a.parent() + Finite Field of size 3 + sage: a = e[1,1].principal_specialization(n=2); a + q^2 + 1 + sage: a.parent() + Univariate Polynomial Ring in q over Finite Field of size 3 + sage: a = e.one().principal_specialization(n=2, q=GF(3)(2)); a + 1 + sage: a.parent() + Finite Field of size 3 + sage: a = e.one().principal_specialization(n=2, q=GF(3)(1)); a + 1 + sage: a.parent() + Finite Field of size 3 + sage: a = e.one().principal_specialization(n=2); a + 1 + sage: a.parent() + Univariate Polynomial Ring in q over Finite Field of size 3 + """ from sage.combinat.q_analogues import q_binomial From bd6ca365ac9918c5118591a72dd325f6c1c48bd0 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 17:48:27 +0200 Subject: [PATCH 135/476] a bit more doc on q-factorials and ex --- src/sage/combinat/q_analogues.py | 12 ++++++++++-- src/sage/combinat/sf/elementary.py | 2 ++ src/sage/combinat/sf/homogeneous.py | 2 ++ src/sage/combinat/sf/monomial.py | 2 ++ src/sage/combinat/sf/powersum.py | 2 ++ src/sage/combinat/sf/schur.py | 2 ++ src/sage/combinat/sf/sfa.py | 2 ++ 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index e096fbbaa87..3228b06f354 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -86,8 +86,16 @@ def q_factorial(n, q=None): """ Return the `q`-analogue of the factorial `n!`. - If `q` is unspecified, then it defaults to using the generator `q` for - a univariate polynomial ring over the integers. + This is the product + + .. MATH:: + + [1]_q [2]_q \cdots [n]_q + = 1 \cdot (1+q) \cdot (1+q+q^2) \cdots (1+q+q^2+\cdots+q^{n-1) . + + If `q` is unspecified, then this function defaults to + using the generator `q` for a univariate polynomial + ring over the integers. EXAMPLES:: diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 3c38c476de7..92fca172b4d 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -468,6 +468,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 4e932fbc94a..119bb957ef4 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -356,6 +356,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 74fc3e856d3..dce57759ed2 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -432,6 +432,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index ba0399a1566..67e9fe0641a 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -852,6 +852,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 5421005f0d1..98459452bd2 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -729,6 +729,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index feb9828a850..f0ceb33db36 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5616,6 +5616,8 @@ def exponential_specialization(self, t=None, q=1): (see :meth:`principal_specialization`). (See (7.29) in [EnumComb2]_.) + The limit of `ex_q` as `q \to 1` is `ex`. + INPUT: - ``t`` (default: ``None``) -- the value to use for `t`; From fa68592d15c2db0e5dbbd50eed7778f50fb5b3c1 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 19:19:23 +0200 Subject: [PATCH 136/476] further corrections --- src/sage/combinat/sf/monomial.py | 5 +---- src/sage/combinat/sf/powersum.py | 4 +++- src/sage/combinat/sf/schur.py | 17 ++++++++++------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index dce57759ed2..b3ffa424f36 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -315,8 +315,6 @@ def condition(part): return len(part) > n return self._expand(condition, n, alphabet) -<<<<<<< HEAD -======= def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. @@ -485,8 +483,7 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) - return self.parent().realization_of().powersum()(self).exponential_specialization(t=t, q=q) ->>>>>>> rebase and correct + return self.parent().realization_of().homogeneous()(self).exponential_specialization(t=t, q=q) # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 67e9fe0641a..325b6ba3b51 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -804,8 +804,10 @@ def get_variable(ring, name): q_lim = PolynomialRing(self.base_ring(), "q").gen() def f(partition): denom = prod((1-q**part) for part in partition) - if denom: + if denom.is_invertible(): return prod((1-q**(n*part)) for part in partition)/denom + # If denom is not invertible, we need to do the + # computation with universal coefficients instead: quotient = prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition) return quotient.subs({q_lim: q}) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 98459452bd2..e8c6c317a31 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -617,7 +617,8 @@ def principal_specialization(self, n=infinity, q=None): ps_{n,1}(s_\lambda) = \prod_{u\in\lambda} (n+c(u)) / h(u), - where `h(u)` is the hook length of a cell `u` in `\lambda`. + where `h(u)` is the hook length of a cell `u` in `\lambda`, + and where `c(u)` is the content of a cell `u` in `\lambda`. For `n=infinity` we use the formula from Corollary 7.21.3 of [EnumComb2]_ @@ -665,7 +666,7 @@ def get_variable(ring, name): if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: (prod(n+partition.content(*c) for c in partition.cells()) + f = lambda partition: (prod(n+j-i for (i, j) in partition.cells()) / prod(h for h in partition.hooks())) elif n == infinity: f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) @@ -675,13 +676,15 @@ def get_variable(ring, name): def f(partition): power = q**sum(i*part for i, part in enumerate(partition)) denom = prod(1-q**h for h in partition.hooks()) - if denom: + if denom.is_invertible(): return (power - * prod(1-q**(n + partition.content(*c)) - for c in partition.cells()) + * prod(1-q**(n+j-i) + for (i, j) in partition.cells()) / denom) - quotient = (prod(1-q_lim**(n + partition.content(*c)) - for c in partition.cells()) + # If denom is not invertible, we need to do the + # computation with universal coefficients instead: + quotient = (prod(1-q_lim**(n+j-i) + for (i, j) in partition.cells()) / prod(1-q_lim**h for h in partition.hooks())) return (power * quotient.subs({q_lim: q})) From 34b78961977e03ec9889729eb54a279450dce6fd Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 19:40:43 +0200 Subject: [PATCH 137/476] oops, there is no is_invertible in general rings --- src/sage/combinat/sf/powersum.py | 8 +++++--- src/sage/combinat/sf/schur.py | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 325b6ba3b51..a112b73fd53 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -804,12 +804,14 @@ def get_variable(ring, name): q_lim = PolynomialRing(self.base_ring(), "q").gen() def f(partition): denom = prod((1-q**part) for part in partition) - if denom.is_invertible(): + try: + ~denom return prod((1-q**(n*part)) for part in partition)/denom # If denom is not invertible, we need to do the # computation with universal coefficients instead: - quotient = prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition) - return quotient.subs({q_lim: q}) + except (ZeroDivisionError, NotImplementedError): + quotient = prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition) + return quotient.subs({q_lim: q}) return self.parent()._apply_module_morphism(self, f, q.parent()) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index e8c6c317a31..faa3b1827e8 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -676,17 +676,19 @@ def get_variable(ring, name): def f(partition): power = q**sum(i*part for i, part in enumerate(partition)) denom = prod(1-q**h for h in partition.hooks()) - if denom.is_invertible(): + try: + ~denom return (power * prod(1-q**(n+j-i) for (i, j) in partition.cells()) / denom) # If denom is not invertible, we need to do the # computation with universal coefficients instead: - quotient = (prod(1-q_lim**(n+j-i) - for (i, j) in partition.cells()) - / prod(1-q_lim**h for h in partition.hooks())) - return (power * quotient.subs({q_lim: q})) + except (ZeroDivisionError, NotImplementedError): + quotient = (prod(1-q_lim**(n+j-i) + for (i, j) in partition.cells()) + / prod(1-q_lim**h for h in partition.hooks())) + return (power * quotient.subs({q_lim: q})) return self.parent()._apply_module_morphism(self, f, q.parent()) From 7c87d10f27ca78039ad3e4bfb1d01c4012e39052 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2020 20:09:09 +0200 Subject: [PATCH 138/476] update references to Grinberg/Reiner (v6 is out) --- src/doc/en/reference/references/index.rst | 2 +- src/sage/combinat/sf/sfa.py | 17 +++++++++++------ src/sage/matroids/matroid.pyx | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index f488f0a8cbb..40038d67665 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2415,7 +2415,7 @@ REFERENCES: .. [GriRei18] Darij Grinberg, Victor Reiner, *Hopf Algebras in Combinatorics*, - :arxiv:`1409.8356v5`. + :arxiv:`1409.8356v6`. .. [GR1989] \A. M. Garsia, C. Reutenauer. *A decomposition of Solomon's descent algebra.* Adv. Math. **77** (1989). diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index f0ceb33db36..b5b5874d69b 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -782,8 +782,9 @@ def gessel_reutenauer(self, lam): Let `\lambda` be a partition. The *Gessel-Reutenauer symmetric function* `\mathbf{GR}_\lambda` corresponding to `\lambda` is the symmetric function denoted `L_\lambda` in - [GR1993]_ and in Exercise 7.89 of [STA]_. It can be defined - in several ways: + [GR1993]_ and in Exercise 7.89 of [STA]_ and denoted + `\mathbf{GR}_\lambda` in Definition 6.6.34 of [GriRei18_]. + It can be defined in several ways: - It is the sum of the monomials `\mathbf{x}_w` over all words `w` over the alphabet @@ -800,15 +801,15 @@ def gessel_reutenauer(self, lam): - It is the sum of the fundamental quasisymmetric functions `F_{\operatorname{Des} \sigma}` over all - permutations `\sigma` which have cycle type `\lambda`. See + permutations `\sigma` that have cycle type `\lambda`. See :class:`sage.combinat.ncsf_qsym.qsym.QuasiSymmetricFunctions.Fundamental` for the definition of fundamental quasisymmetric functions, and :meth:`~sage.combinat.permutation.Permutation.cycle_type` for that of cycle type. For a permutation `\sigma`, we use `\operatorname{Des} \sigma` to denote the descent composition (:meth:`~sage.combinat.permutation.Permutation.descents_composition`) - of `\sigma`. Again, this definition makes the symmetry - of `\mathbf{GR}_\lambda` far from obvious. + of `\sigma`. Again, this definition does not make the + symmetry of `\mathbf{GR}_\lambda` obvious. - For every positive integer `n`, we have @@ -834,7 +835,9 @@ def gessel_reutenauer(self, lam): `\mathbf{GR}_\lambda` obvious. The equivalences of these three definitions are proven in - [GR1993]_ Sections 2-3. + [GR1993]_ Sections 2-3. (See also [GriRei18]_ Subsection + 6.6.2 for the equivalence of the first two definitions and + further formulas.) INPUT: @@ -855,6 +858,8 @@ def gessel_reutenauer(self, lam): Journal of Combinatorial Theory, Series A, 64 (1993), pp. 189--215. + .. [GriRei18]_ + EXAMPLES: The first few values of `\mathbf{GR}_{(n)} = L_n`:: diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 8c9753554aa..d274d9eec53 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6623,7 +6623,7 @@ cdef class Matroid(SageObject): sage: M.is_max_weight_independent_generic() False - Here is an example from [GriRei18]_ (Example 7.4.12 in v5):: + Here is an example from [GriRei18]_ (Example 7.4.12 in v6):: sage: A = Matrix(QQ, [[ 1, 1, 0, 0], ....: [-1, 0, 1, 1], @@ -6781,7 +6781,7 @@ cdef class Matroid(SageObject): sage: M.dual().is_max_weight_coindependent_generic(weights=wt) True - Here is an example from [GriRei18]_ (Example 7.4.12 in v5):: + Here is an example from [GriRei18]_ (Example 7.4.12 in v6):: sage: A = Matrix(QQ, [[ 1, 1, 0, 0], ....: [-1, 0, 1, 1], From 4efc8c4860a8c35974fdfc393aeb559bee716b99 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 25 Apr 2020 13:40:07 +0200 Subject: [PATCH 139/476] this way? --- src/sage/combinat/sf/monomial.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index b3ffa424f36..a2d94beefc2 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -387,7 +387,7 @@ def principal_specialization(self, n=infinity, q=None): f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) return self.parent()._apply_module_morphism(self, f, q.parent()) - return self.parent().realization_of().homogeneous()(self).principal_specialization(n=n, q=q) + return self.parent().realization_of().elementary()(self).principal_specialization(n=n, q=q) def exponential_specialization(self, t=None, q=1): r""" @@ -483,7 +483,7 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) - return self.parent().realization_of().homogeneous()(self).exponential_specialization(t=t, q=q) + return self.parent().realization_of().elementary()(self).exponential_specialization(t=t, q=q) # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override From 9084ab38fee9e83710a17098265edc9a239ddd21 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 24 Apr 2020 21:08:31 +0200 Subject: [PATCH 140/476] fix two doctests --- src/sage/combinat/sf/elementary.py | 4 ++-- src/sage/combinat/sf/sfa.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 92fca172b4d..ac6f4a483d5 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -381,8 +381,8 @@ def principal_specialization(self, n=infinity, q=None): 0 sage: a.parent() Finite Field of size 3 - sage: a = e[1,1].principal_specialization(n=2); a - q^2 + 1 + sage: a = e[1,1,1].principal_specialization(n=2); a + q^3 + 1 sage: a.parent() Univariate Polynomial Ring in q over Finite Field of size 3 sage: a = e.one().principal_specialization(n=2, q=GF(3)(2)); a diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index b5b5874d69b..a9c2f786d0e 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5572,7 +5572,7 @@ def principal_specialization(self, n=infinity, q=None): sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: m = S.m(); x = m[3,2,1] sage: set([b(x).principal_specialization(n=4, q=GF(3)(2)) for b in B]) - {-3} # Please replace by correct answer + {1} """ # heuristically, it seems fastest to fall back to the From d0be31457016a3097f21ddccdee6a8ee89193672 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 25 Apr 2020 17:35:46 +0200 Subject: [PATCH 141/476] replacing ring[name] --- src/sage/combinat/sf/elementary.py | 6 ++++-- src/sage/combinat/sf/homogeneous.py | 6 ++++-- src/sage/combinat/sf/monomial.py | 3 ++- src/sage/combinat/sf/powersum.py | 6 ++++-- src/sage/combinat/sf/schur.py | 6 ++++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index ac6f4a483d5..4a8ab9dd87d 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -405,7 +405,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -501,7 +502,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 119bb957ef4..cdff9116db5 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -296,7 +296,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -398,7 +399,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index a2d94beefc2..788a0903ca4 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -466,7 +466,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index a112b73fd53..fc02927d72a 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -787,7 +787,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -892,7 +893,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index faa3b1827e8..373d89bda61 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -657,7 +657,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -790,7 +791,8 @@ def get_variable(ring, name): try: ring(name) except TypeError: - return ring[name].gen() + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) From 8c288fa19272f7c43d9cbaf3af59f9b66243bd65 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 25 Apr 2020 21:24:36 +0200 Subject: [PATCH 142/476] fix doctest, fix comments --- src/sage/combinat/sf/monomial.py | 8 +++++++- src/sage/combinat/sf/sfa.py | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 788a0903ca4..d34de07096d 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -373,7 +373,7 @@ def principal_specialization(self, n=infinity, q=None): sage: x = 5*m[2] + 3*m[1] + 1 sage: x.principal_specialization(3, q=var("q")) - 5*(q^6 - 1)/(q^2 - 1) + 3*(q^3 - 1)/(q - 1) + 1 + -10*(q^3 - 1)*q/(q - 1) + 5*(q^3 - 1)^2/(q - 1)^2 + 3*(q^3 - 1)/(q - 1) + 1 TESTS:: @@ -387,6 +387,9 @@ def principal_specialization(self, n=infinity, q=None): f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) return self.parent()._apply_module_morphism(self, f, q.parent()) + # heuristically, it seems fastest to fall back to the + # elementary basis - using the powersum basis would + # introduce singularities, because it is not a Z-basis return self.parent().realization_of().elementary()(self).principal_specialization(n=n, q=q) def exponential_specialization(self, t=None, q=1): @@ -484,6 +487,9 @@ def f(partition): return self.parent()._apply_module_morphism(self, f, t.parent()) + # heuristically, it seems fastest to fall back to the + # elementary basis - using the powersum basis would + # introduce singularities, because it is not a Z-basis return self.parent().realization_of().elementary()(self).exponential_specialization(t=t, q=q) # Backward compatibility for unpickling diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index a9c2f786d0e..76f906d71db 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5576,7 +5576,8 @@ def principal_specialization(self, n=infinity, q=None): """ # heuristically, it seems fastest to fall back to the - # elementary basis instead of the powersum basis + # elementary basis - using the powersum basis would + # introduce singularities, because it is not a Z-basis e = self.parent().realization_of().elementary() return e(self).principal_specialization(n, q=q) @@ -5671,7 +5672,8 @@ def exponential_specialization(self, t=None, q=1): """ # heuristically, it seems fastest to fall back to the - # elementary basis instead of the powersum basis + # elementary basis - using the powersum basis would + # introduce singularities, because it is not a Z-basis e = self.parent().realization_of().elementary() return e(self).exponential_specialization(t=t, q=q) From c37c530505daaa7e701cdfacf498007457c12b07 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 25 Apr 2020 22:05:23 +0200 Subject: [PATCH 143/476] test battery for principal_specialization --- src/sage/combinat/sf/elementary.py | 22 -------- src/sage/combinat/sf/sfa.py | 89 +++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 4a8ab9dd87d..cdc6da8f29e 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -376,28 +376,6 @@ def principal_specialization(self, n=infinity, q=None): sage: e.zero().principal_specialization(3) 0 - sage: e = SymmetricFunctions(GF(3)).e() - sage: a = e[2,1].principal_specialization(n=2, q=GF(3)(2)); a - 0 - sage: a.parent() - Finite Field of size 3 - sage: a = e[1,1,1].principal_specialization(n=2); a - q^3 + 1 - sage: a.parent() - Univariate Polynomial Ring in q over Finite Field of size 3 - sage: a = e.one().principal_specialization(n=2, q=GF(3)(2)); a - 1 - sage: a.parent() - Finite Field of size 3 - sage: a = e.one().principal_specialization(n=2, q=GF(3)(1)); a - 1 - sage: a.parent() - Finite Field of size 3 - sage: a = e.one().principal_specialization(n=2); a - 1 - sage: a.parent() - Univariate Polynomial Ring in q over Finite Field of size 3 - """ from sage.combinat.q_analogues import q_binomial diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 76f906d71db..4f8c551f02b 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5569,11 +5569,98 @@ def principal_specialization(self, n=infinity, q=None): {-3} sage: S = SymmetricFunctions(GF(3)) - sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] sage: m = S.m(); x = m[3,2,1] sage: set([b(x).principal_specialization(n=4, q=GF(3)(2)) for b in B]) {1} + sage: S = SymmetricFunctions(Zmod(4)) + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: m = S.m(); x = m[3,2,1] + sage: set([b(x).principal_specialization(n=4, q=Zmod(4)(2)) for b in B]) + {0} + sage: y = m[3,1] + sage: set([b(y).principal_specialization(n=4, q=Zmod(4)(2)) for b in B]) + {2} + + Check that parents are correct over `\mathbb{F}_3`:: + + sage: S = SymmetricFunctions(GF(3)) + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].principal_specialization(n=2, q=GF(3)(0)).parent() for b in B for lam in lams) + {Finite Field of size 3} + sage: set(b[lam].principal_specialization(n=2, q=GF(3)(1)).parent() for b in B for lam in lams) + {Finite Field of size 3} + sage: set(b[lam].principal_specialization(n=2, q=GF(3)(2)).parent() for b in B for lam in lams) + {Finite Field of size 3} + sage: set(b[lam].principal_specialization(n=2).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Finite Field of size 3} + sage: set(b[lam].principal_specialization().parent() for b in B for lam in lams) + {Fraction Field of Univariate Polynomial Ring in q over Finite Field of size 3} + + sage: a = S.e()[2,1].principal_specialization(n=2, q=GF(3)(2)); a + 0 + sage: a = S.e()[1,1,1].principal_specialization(n=2); a + q^3 + 1 + + sage: set(b.one().principal_specialization(n=2, q=GF(3)(2)) for b in B) + {1} + sage: set(b.one().principal_specialization(n=2, q=GF(3)(1)) for b in B) + {1} + sage: set(b.one().principal_specialization(n=2) for b in B) + {1} + sage: set(b.one().principal_specialization() for b in B) + {1} + + Check that parents are correct over the integer ring:: + + sage: S = SymmetricFunctions(ZZ) + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].principal_specialization(n=2, q=0).parent() for b in B for lam in lams) + {Integer Ring} + sage: set(b[lam].principal_specialization(n=2, q=1).parent() for b in B for lam in lams) + {Integer Ring} + sage: set(b[lam].principal_specialization(n=2, q=2).parent() for b in B for lam in lams) + {Integer Ring} + sage: set(b[lam].principal_specialization(n=2).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} + sage: set(b[lam].principal_specialization().parent() for b in B for lam in lams) + {Fraction Field of Univariate Polynomial Ring in q over Integer Ring} + + Check that parents are correct over a polynomial ring:: + + sage: P = PolynomialRing(ZZ, "q") + sage: q = P.gen() + sage: S = SymmetricFunctions(P) + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].principal_specialization(n=2, q=P(0)).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} + sage: set(b[lam].principal_specialization(n=2, q=P(1)).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} + sage: set(b[lam].principal_specialization(n=2, q=P(2)).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} + sage: set(b[lam].principal_specialization(n=2, q=q).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} + sage: set(b[lam].principal_specialization(q=q).parent() for b in B for lam in lams) + {Fraction Field of Univariate Polynomial Ring in q over Integer Ring} + + sage: a = S.e()[2,1].principal_specialization(n=2, q=2); a + 6 + sage: a = S.e()[2,1].principal_specialization(n=2, q=q); a + q**2 + q + + sage: set(b.one().principal_specialization(n=2, q=P(2)) for b in B) + {1} + sage: set(b.one().principal_specialization(n=2, q=P(1)) for b in B) + {1} + sage: set(b.one().principal_specialization(n=2, q=q) for b in B) + {1} + sage: set(b.one().principal_specialization(q=q) for b in B) + {1} + """ # heuristically, it seems fastest to fall back to the # elementary basis - using the powersum basis would From 1ab1097f1aa12b10f1144e7e3b02bd349b0e8026 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 25 Apr 2020 23:37:57 +0200 Subject: [PATCH 144/476] attempt at fixing schur principal_spec --- src/sage/combinat/sf/schur.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 373d89bda61..17938743f66 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -673,8 +673,11 @@ def get_variable(ring, name): f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) / prod(1-q**h for h in partition.hooks())) else: - q_lim = PolynomialRing(self.base_ring(), "q").gen() + ZZq = PolynomialRing(ZZ, "q").gen() + q_lim = ZZq.gen() def f(partition): + if n < len(partition): + return 0 power = q**sum(i*part for i, part in enumerate(partition)) denom = prod(1-q**h for h in partition.hooks()) try: @@ -686,8 +689,8 @@ def f(partition): # If denom is not invertible, we need to do the # computation with universal coefficients instead: except (ZeroDivisionError, NotImplementedError): - quotient = (prod(1-q_lim**(n+j-i) - for (i, j) in partition.cells()) + quotient = ZZq((prod(1-q_lim**(n+j-i) + for (i, j) in partition.cells())) / prod(1-q_lim**h for h in partition.hooks())) return (power * quotient.subs({q_lim: q})) From d67dadd25d965fc77746dba6dc2f61041b915528 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 26 Apr 2020 00:03:34 +0200 Subject: [PATCH 145/476] fix quotients --- src/sage/combinat/sf/schur.py | 20 +++++++++++--------- src/sage/combinat/sf/sfa.py | 20 ++++++++++++++------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 17938743f66..4e020edcd77 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -668,12 +668,13 @@ def get_variable(ring, name): if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: (prod(n+j-i for (i, j) in partition.cells()) - / prod(h for h in partition.hooks())) + // prod(h for h in partition.hooks())) elif n == infinity: f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) / prod(1-q**h for h in partition.hooks())) else: - ZZq = PolynomialRing(ZZ, "q").gen() + from sage.rings.integer_ring import ZZ + ZZq = PolynomialRing(ZZ, "q") q_lim = ZZq.gen() def f(partition): if n < len(partition): @@ -682,13 +683,14 @@ def f(partition): denom = prod(1-q**h for h in partition.hooks()) try: ~denom - return (power - * prod(1-q**(n+j-i) - for (i, j) in partition.cells()) - / denom) - # If denom is not invertible, we need to do the - # computation with universal coefficients instead: - except (ZeroDivisionError, NotImplementedError): + rational = (power + * prod(1-q**(n+j-i) + for (i, j) in partition.cells()) + / denom) + return q.parent()(rational) + except (ZeroDivisionError, NotImplementedError, TypeError): + # If denom is not invertible, we need to do the + # computation with universal coefficients instead: quotient = ZZq((prod(1-q_lim**(n+j-i) for (i, j) in partition.cells())) / prod(1-q_lim**h for h in partition.hooks())) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 4f8c551f02b..a97cafa3b5f 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5582,6 +5582,9 @@ def principal_specialization(self, n=infinity, q=None): sage: y = m[3,1] sage: set([b(y).principal_specialization(n=4, q=Zmod(4)(2)) for b in B]) {2} + sage: z = m[1,1] + sage: set([b(z).principal_specialization(n=4) for b in B]) + {q^5 + q^4 + 2*q^3 + q^2 + q} Check that parents are correct over `\mathbb{F}_3`:: @@ -5597,13 +5600,14 @@ def principal_specialization(self, n=infinity, q=None): sage: set(b[lam].principal_specialization(n=2).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Finite Field of size 3} sage: set(b[lam].principal_specialization().parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Finite Field of size 3} + {Fraction Field of Univariate Polynomial Ring in q over Finite Field of size 3, + Univariate Polynomial Ring in q over Finite Field of size 3} sage: a = S.e()[2,1].principal_specialization(n=2, q=GF(3)(2)); a 0 sage: a = S.e()[1,1,1].principal_specialization(n=2); a q^3 + 1 - + sage: set(b.one().principal_specialization(n=2, q=GF(3)(2)) for b in B) {1} sage: set(b.one().principal_specialization(n=2, q=GF(3)(1)) for b in B) @@ -5627,7 +5631,9 @@ def principal_specialization(self, n=infinity, q=None): sage: set(b[lam].principal_specialization(n=2).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Integer Ring} sage: set(b[lam].principal_specialization().parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Integer Ring} + {Fraction Field of Univariate Polynomial Ring in q over Integer Ring, + Univariate Polynomial Ring in q over Integer Ring, + Univariate Polynomial Ring in q over Rational Field} Check that parents are correct over a polynomial ring:: @@ -5645,13 +5651,15 @@ def principal_specialization(self, n=infinity, q=None): sage: set(b[lam].principal_specialization(n=2, q=q).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Integer Ring} sage: set(b[lam].principal_specialization(q=q).parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Integer Ring} + {Fraction Field of Univariate Polynomial Ring in q over Integer Ring, + Univariate Polynomial Ring in q over Integer Ring, + Univariate Polynomial Ring in q over Rational Field} sage: a = S.e()[2,1].principal_specialization(n=2, q=2); a 6 sage: a = S.e()[2,1].principal_specialization(n=2, q=q); a - q**2 + q - + q^2 + q + sage: set(b.one().principal_specialization(n=2, q=P(2)) for b in B) {1} sage: set(b.one().principal_specialization(n=2, q=P(1)) for b in B) From b283d231be19a63f0df2fb5eb7e94b456ac523bc Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 00:12:48 +0200 Subject: [PATCH 146/476] similar changes to powersum --- src/sage/combinat/sf/powersum.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index fc02927d72a..1c3b50edb74 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -802,16 +802,19 @@ def get_variable(ring, name): elif n == infinity: f = lambda partition: prod(1/(1-q**part) for part in partition) else: - q_lim = PolynomialRing(self.base_ring(), "q").gen() + from sage.rings.integer_ring import ZZ + ZZq = PolynomialRing(ZZ, "q") + q_lim = ZZq.gen() def f(partition): denom = prod((1-q**part) for part in partition) try: ~denom - return prod((1-q**(n*part)) for part in partition)/denom - # If denom is not invertible, we need to do the - # computation with universal coefficients instead: - except (ZeroDivisionError, NotImplementedError): - quotient = prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition) + rational = prod((1-q**(n*part)) for part in partition)/denom + return q.parent()(rational) + except (ZeroDivisionError, NotImplementedError, TypeError): + # If denom is not invertible, we need to do the + # computation with universal coefficients instead: + quotient = ZZq(prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition)) return quotient.subs({q_lim: q}) return self.parent()._apply_module_morphism(self, f, q.parent()) From 0e2f95ce92868be51c8c8b21ebfe1a6b74f52eda Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 26 Apr 2020 00:13:50 +0200 Subject: [PATCH 147/476] add doctests for powersums --- src/sage/combinat/sf/sfa.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index a97cafa3b5f..1ad966a36b1 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5569,19 +5569,20 @@ def principal_specialization(self, n=infinity, q=None): {-3} sage: S = SymmetricFunctions(GF(3)) - sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: m = S.m(); x = m[3,2,1] sage: set([b(x).principal_specialization(n=4, q=GF(3)(2)) for b in B]) {1} sage: S = SymmetricFunctions(Zmod(4)) - sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: m = S.m(); x = m[3,2,1] sage: set([b(x).principal_specialization(n=4, q=Zmod(4)(2)) for b in B]) {0} sage: y = m[3,1] sage: set([b(y).principal_specialization(n=4, q=Zmod(4)(2)) for b in B]) {2} + sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] sage: z = m[1,1] sage: set([b(z).principal_specialization(n=4) for b in B]) {q^5 + q^4 + 2*q^3 + q^2 + q} @@ -5589,7 +5590,7 @@ def principal_specialization(self, n=infinity, q=None): Check that parents are correct over `\mathbb{F}_3`:: sage: S = SymmetricFunctions(GF(3)) - sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] sage: set(b[lam].principal_specialization(n=2, q=GF(3)(0)).parent() for b in B for lam in lams) {Finite Field of size 3} @@ -5620,7 +5621,7 @@ def principal_specialization(self, n=infinity, q=None): Check that parents are correct over the integer ring:: sage: S = SymmetricFunctions(ZZ) - sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] sage: set(b[lam].principal_specialization(n=2, q=0).parent() for b in B for lam in lams) {Integer Ring} @@ -5640,7 +5641,7 @@ def principal_specialization(self, n=infinity, q=None): sage: P = PolynomialRing(ZZ, "q") sage: q = P.gen() sage: S = SymmetricFunctions(P) - sage: B = [S.m(), S.e(), S.h(), S.s(), S.f()] + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] sage: set(b[lam].principal_specialization(n=2, q=P(0)).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Integer Ring} From e16d5249d729fa50350a8f7e1a4d3b6c4aedfe79 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 00:55:51 +0200 Subject: [PATCH 148/476] attempt at a test battery for exponential specialization --- src/sage/combinat/sf/elementary.py | 4 +- src/sage/combinat/sf/homogeneous.py | 4 +- src/sage/combinat/sf/monomial.py | 4 +- src/sage/combinat/sf/powersum.py | 4 +- src/sage/combinat/sf/schur.py | 4 +- src/sage/combinat/sf/sfa.py | 57 ++++++++++++++++++++++++++++- 6 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index cdc6da8f29e..678e065d96b 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -408,7 +408,9 @@ def get_variable(ring, name): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index cdff9116db5..497e30bf709 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -318,7 +318,9 @@ def get_variable(ring, name): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index d34de07096d..1fe6fe1729e 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -394,7 +394,9 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 1c3b50edb74..63cd8165d76 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -821,7 +821,9 @@ def f(partition): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 4e020edcd77..a45c28ea5a1 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -701,7 +701,9 @@ def f(partition): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 1ad966a36b1..a7898a7d40c 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5679,7 +5679,9 @@ def principal_specialization(self, n=infinity, q=None): def exponential_specialization(self, t=None, q=1): r""" - Return the exponential specialization of a symmetric function. + Return the exponential specialization of a + symmetric function (when `q = 1`), or the + `q`-exponential specialization (when `q \neq 1`). The *exponential specialization* `ex` at `t` is a `K`-algebra homomorphism from the `K`-algebra of @@ -5734,6 +5736,17 @@ def exponential_specialization(self, t=None, q=1): sage: m = SymmetricFunctions(QQ).m() sage: (m[2,1]+m[1,1]).exponential_specialization() 1/2*t^2 + sage: (m[2,1]+m[1,1]).exponential_specialization(q=None) + t**2 * (1 - q)/(1 + q) + sage: Qq = PolynomialRing(QQ, "q"); q = Qq.gen() + sage: (m[2,1]+m[1,1]).exponential_specialization(q=q) + t**2 * (1 - q)/(1 + q) + sage: Qt = PolynomialRing(QQ, "t"); t = Qt.gen() + sage: (m[2,1]+m[1,1]).exponential_specialization(t=t) + t**2 * (1 - q)/(1 + q) + sage: Qqt = PolynomialRing(QQ, ["q", "t"]); q, t = Qqt.gens() + sage: (m[2,1]+m[1,1]).exponential_specialization(q=q, t=t) + t**2 * (1 - q)/(1 + q) sage: x = m[3]+m[2,1]+m[1,1,1] sage: d = x.homogeneous_degree() @@ -5766,6 +5779,48 @@ def exponential_specialization(self, t=None, q=1): sage: len(set([b(x).exponential_specialization(t=2) for b in B])) 1 + Check that parents are correct over `\mathbb{F}_3`:: + + sage: S = SymmetricFunctions(GF(3)) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].exponential_specialization(q=None).parent() for b in B for lam in lams) + {Fraction Field of Univariate Polynomial Ring in t over + Univariate Polynomial Ring in q over Finite Field of size 3, + Univariate Polynomial Ring in t over Univariate Polynomial Ring in q + over Finite Field of size 3} + sage: P2 = PolynomialRing(GF(3), ["q", "t"]) + sage: q2, t2 = P2.gens() + sage: set(b[lam].exponential_specialization(q=q2, t=t2).parent() for b in B for lam in lams) + {Fraction Field of Multivariate Polynomial Ring in q, t over Finite Field of size 3, + Multivariate Polynomial Ring in q, t over Finite Field of size 3} + + Check that parents are correct over `\QQ` for `q = 1`:: + + sage: S = SymmetricFunctions(QQ) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].exponential_specialization(q=1).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in t over Rational Field} + sage: set(b[lam].exponential_specialization(q=1, t=1).parent() for b in B for lam in lams) + {Rational Field} + sage: P2 = PolynomialRing(QQ, ["q", "t"]) + sage: q2, t2 = P2.gens() + sage: set(b[lam].exponential_specialization(q=1, t=t2).parent() for b in B for lam in lams) + {Multivariate Polynomial Ring in q, t over Rational Field} + + Check that parents are correct over a polynomial ring:: + + sage: P = PolynomialRing(QQ, "q") + sage: q = P.gen() + sage: S = SymmetricFunctions(P) + sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] + sage: lams = [Partition([]), Partition([1]), Partition([2,1])] + sage: set(b[lam].exponential_specialization(q=q).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in t over + Univariate Polynomial Ring in q over Rational Field} + sage: set(b[lam].exponential_specialization(q=q, t=1).parent() for b in B for lam in lams) + {Univariate Polynomial Ring in q over Integer Ring} """ # heuristically, it seems fastest to fall back to the # elementary basis - using the powersum basis would From 97777402bbb51b0592e2b53bfb06fbea583a8def Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 09:29:35 +0200 Subject: [PATCH 149/476] fix doctests --- src/sage/combinat/sf/sfa.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index a7898a7d40c..57a829c5403 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5736,17 +5736,17 @@ def exponential_specialization(self, t=None, q=1): sage: m = SymmetricFunctions(QQ).m() sage: (m[2,1]+m[1,1]).exponential_specialization() 1/2*t^2 - sage: (m[2,1]+m[1,1]).exponential_specialization(q=None) - t**2 * (1 - q)/(1 + q) + sage: m[1,1].exponential_specialization(q=None) + 1/2*t^2 sage: Qq = PolynomialRing(QQ, "q"); q = Qq.gen() - sage: (m[2,1]+m[1,1]).exponential_specialization(q=q) - t**2 * (1 - q)/(1 + q) + sage: m[1,1].exponential_specialization(q=q) + t^2 * (1 - q)/(1 + q) sage: Qt = PolynomialRing(QQ, "t"); t = Qt.gen() - sage: (m[2,1]+m[1,1]).exponential_specialization(t=t) - t**2 * (1 - q)/(1 + q) + sage: m[1,1].exponential_specialization(t=t) + 1/2*t^2 sage: Qqt = PolynomialRing(QQ, ["q", "t"]); q, t = Qqt.gens() - sage: (m[2,1]+m[1,1]).exponential_specialization(q=q, t=t) - t**2 * (1 - q)/(1 + q) + sage: m[1,1].exponential_specialization(q=q, t=t) + t^2 * (1 - q)/(1 + q) sage: x = m[3]+m[2,1]+m[1,1,1] sage: d = x.homogeneous_degree() @@ -5785,10 +5785,10 @@ def exponential_specialization(self, t=None, q=1): sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] sage: set(b[lam].exponential_specialization(q=None).parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in t over - Univariate Polynomial Ring in q over Finite Field of size 3, - Univariate Polynomial Ring in t over Univariate Polynomial Ring in q - over Finite Field of size 3} + {Univariate Polynomial Ring in t over Fraction Field + of Univariate Polynomial Ring in q over Finite Field of size 3, + Univariate Polynomial Ring in t over Univariate Polynomial Ring + in q over Finite Field of size 3} sage: P2 = PolynomialRing(GF(3), ["q", "t"]) sage: q2, t2 = P2.gens() sage: set(b[lam].exponential_specialization(q=q2, t=t2).parent() for b in B for lam in lams) @@ -5818,9 +5818,12 @@ def exponential_specialization(self, t=None, q=1): sage: lams = [Partition([]), Partition([1]), Partition([2,1])] sage: set(b[lam].exponential_specialization(q=q).parent() for b in B for lam in lams) {Univariate Polynomial Ring in t over - Univariate Polynomial Ring in q over Rational Field} + Fraction Field of Univariate Polynomial Ring in q over Rational Field, + Univariate Polynomial Ring in t over Univariate Polynomial Ring + in q over Rational Field} sage: set(b[lam].exponential_specialization(q=q, t=1).parent() for b in B for lam in lams) - {Univariate Polynomial Ring in q over Integer Ring} + {Fraction Field of Univariate Polynomial Ring in q over Rational Field, + Univariate Polynomial Ring in q over Rational Field} """ # heuristically, it seems fastest to fall back to the # elementary basis - using the powersum basis would From ab684e74e9bf8e622843de3bbfe5fed1e1a6b7b7 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 12:26:13 +0200 Subject: [PATCH 150/476] fix doctests --- src/sage/combinat/sf/sfa.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 57a829c5403..c051ad385ae 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5736,17 +5736,19 @@ def exponential_specialization(self, t=None, q=1): sage: m = SymmetricFunctions(QQ).m() sage: (m[2,1]+m[1,1]).exponential_specialization() 1/2*t^2 - sage: m[1,1].exponential_specialization(q=None) + sage: (m[2,1]+m[1,1]).exponential_specialization(q=1) 1/2*t^2 + sage: m[1,1].exponential_specialization(q=None) + (q/(q + 1))*t^2 sage: Qq = PolynomialRing(QQ, "q"); q = Qq.gen() sage: m[1,1].exponential_specialization(q=q) - t^2 * (1 - q)/(1 + q) + (q/(q + 1))*t^2 sage: Qt = PolynomialRing(QQ, "t"); t = Qt.gen() sage: m[1,1].exponential_specialization(t=t) 1/2*t^2 sage: Qqt = PolynomialRing(QQ, ["q", "t"]); q, t = Qqt.gens() sage: m[1,1].exponential_specialization(q=q, t=t) - t^2 * (1 - q)/(1 + q) + q*t^2/(q + 1) sage: x = m[3]+m[2,1]+m[1,1,1] sage: d = x.homogeneous_degree() @@ -5792,8 +5794,8 @@ def exponential_specialization(self, t=None, q=1): sage: P2 = PolynomialRing(GF(3), ["q", "t"]) sage: q2, t2 = P2.gens() sage: set(b[lam].exponential_specialization(q=q2, t=t2).parent() for b in B for lam in lams) - {Fraction Field of Multivariate Polynomial Ring in q, t over Finite Field of size 3, - Multivariate Polynomial Ring in q, t over Finite Field of size 3} + {Multivariate Polynomial Ring in q, t over Finite Field of size 3, + Fraction Field of Multivariate Polynomial Ring in q, t over Finite Field of size 3} Check that parents are correct over `\QQ` for `q = 1`:: From db1704513d5a2a0138bfabb94a409f6439f1d220 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 12:31:32 +0200 Subject: [PATCH 151/476] follow Travis's suggestion about set output --- src/sage/combinat/sf/sfa.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index c051ad385ae..2d2f866ccea 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -5631,10 +5631,10 @@ def principal_specialization(self, n=infinity, q=None): {Integer Ring} sage: set(b[lam].principal_specialization(n=2).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Integer Ring} - sage: set(b[lam].principal_specialization().parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Integer Ring, + sage: sorted(set(b[lam].principal_specialization().parent() for b in B for lam in lams), key=str) + [Fraction Field of Univariate Polynomial Ring in q over Integer Ring, Univariate Polynomial Ring in q over Integer Ring, - Univariate Polynomial Ring in q over Rational Field} + Univariate Polynomial Ring in q over Rational Field] Check that parents are correct over a polynomial ring:: @@ -5651,10 +5651,10 @@ def principal_specialization(self, n=infinity, q=None): {Univariate Polynomial Ring in q over Integer Ring} sage: set(b[lam].principal_specialization(n=2, q=q).parent() for b in B for lam in lams) {Univariate Polynomial Ring in q over Integer Ring} - sage: set(b[lam].principal_specialization(q=q).parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Integer Ring, + sage: sorted(set(b[lam].principal_specialization(q=q).parent() for b in B for lam in lams), key=str) + [Fraction Field of Univariate Polynomial Ring in q over Integer Ring, Univariate Polynomial Ring in q over Integer Ring, - Univariate Polynomial Ring in q over Rational Field} + Univariate Polynomial Ring in q over Rational Field] sage: a = S.e()[2,1].principal_specialization(n=2, q=2); a 6 @@ -5786,16 +5786,16 @@ def exponential_specialization(self, t=None, q=1): sage: S = SymmetricFunctions(GF(3)) sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] - sage: set(b[lam].exponential_specialization(q=None).parent() for b in B for lam in lams) - {Univariate Polynomial Ring in t over Fraction Field + sage: sorted(set(b[lam].exponential_specialization(q=None).parent() for b in B for lam in lams), key=str) + [Univariate Polynomial Ring in t over Fraction Field of Univariate Polynomial Ring in q over Finite Field of size 3, Univariate Polynomial Ring in t over Univariate Polynomial Ring - in q over Finite Field of size 3} + in q over Finite Field of size 3] sage: P2 = PolynomialRing(GF(3), ["q", "t"]) sage: q2, t2 = P2.gens() - sage: set(b[lam].exponential_specialization(q=q2, t=t2).parent() for b in B for lam in lams) - {Multivariate Polynomial Ring in q, t over Finite Field of size 3, - Fraction Field of Multivariate Polynomial Ring in q, t over Finite Field of size 3} + sage: sorted(set(b[lam].exponential_specialization(q=q2, t=t2).parent() for b in B for lam in lams), key=str) + [Fraction Field of Multivariate Polynomial Ring in q, t over Finite Field of size 3, + Multivariate Polynomial Ring in q, t over Finite Field of size 3] Check that parents are correct over `\QQ` for `q = 1`:: @@ -5818,14 +5818,14 @@ def exponential_specialization(self, t=None, q=1): sage: S = SymmetricFunctions(P) sage: B = [S.p(), S.m(), S.e(), S.h(), S.s(), S.f()] sage: lams = [Partition([]), Partition([1]), Partition([2,1])] - sage: set(b[lam].exponential_specialization(q=q).parent() for b in B for lam in lams) - {Univariate Polynomial Ring in t over + sage: sorted(set(b[lam].exponential_specialization(q=q).parent() for b in B for lam in lams), key=str) + [Univariate Polynomial Ring in t over Fraction Field of Univariate Polynomial Ring in q over Rational Field, Univariate Polynomial Ring in t over Univariate Polynomial Ring - in q over Rational Field} - sage: set(b[lam].exponential_specialization(q=q, t=1).parent() for b in B for lam in lams) - {Fraction Field of Univariate Polynomial Ring in q over Rational Field, - Univariate Polynomial Ring in q over Rational Field} + in q over Rational Field] + sage: sorted(set(b[lam].exponential_specialization(q=q, t=1).parent() for b in B for lam in lams), key=str) + [Fraction Field of Univariate Polynomial Ring in q over Rational Field, + Univariate Polynomial Ring in q over Rational Field] """ # heuristically, it seems fastest to fall back to the # elementary basis - using the powersum basis would From f55e4d96fb4e67fe23c4252d29a26ff9a0732c6e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 26 Apr 2020 17:49:42 +0200 Subject: [PATCH 152/476] oops --- src/sage/combinat/q_analogues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index 3228b06f354..8d9016cc65e 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -91,7 +91,7 @@ def q_factorial(n, q=None): .. MATH:: [1]_q [2]_q \cdots [n]_q - = 1 \cdot (1+q) \cdot (1+q+q^2) \cdots (1+q+q^2+\cdots+q^{n-1) . + = 1 \cdot (1+q) \cdot (1+q+q^2) \cdots (1+q+q^2+\cdots+q^{n-1}) . If `q` is unspecified, then this function defaults to using the generator `q` for a univariate polynomial From cf9e0f2802032941595f0b25b9d090da04939bfa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 27 Apr 2020 20:53:57 -0700 Subject: [PATCH 153/476] src/sage/combinat/sf/sfa.py: Fixup markup in docstring --- src/sage/combinat/sf/sfa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 2d2f866ccea..051bd64e6a8 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -783,7 +783,7 @@ def gessel_reutenauer(self, lam): symmetric function* `\mathbf{GR}_\lambda` corresponding to `\lambda` is the symmetric function denoted `L_\lambda` in [GR1993]_ and in Exercise 7.89 of [STA]_ and denoted - `\mathbf{GR}_\lambda` in Definition 6.6.34 of [GriRei18_]. + `\mathbf{GR}_\lambda` in Definition 6.6.34 of [GriRei18]_. It can be defined in several ways: - It is the sum of the monomials `\mathbf{x}_w` over all From edbb69d6f02364d6586e432bd165513d9122523a Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 3 May 2020 13:35:30 +0200 Subject: [PATCH 154/476] 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 e8f2f9fd7d9ed913c5aff3164faf15d2a543fd00 Mon Sep 17 00:00:00 2001 From: rbmj Date: Sun, 3 May 2020 11:44:17 -0400 Subject: [PATCH 155/476] Moved exponential sampling to _plot() and added documentation in plot_semilogx() --- src/sage/plot/plot.py | 85 +++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index df1528f8632..6697b5c9cd6 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -591,7 +591,6 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 from sage.misc.randstate import current_randstate #for plot adaptive refinement from math import sin, cos, pi, log, exp #for polar_plot and log scaling - from sage.ext.fast_eval import fast_float, is_fast_float from sage.misc.decorators import options @@ -1947,11 +1946,9 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) raise ValueError('only one of color or rgbcolor should be specified') elif 'color' in kwds: kwds['rgbcolor'] = kwds.pop('color', (0,0,1)) # take blue as default ``rgbcolor`` - G_kwds = Graphics._extract_kwds_for_show(kwds, ignore=['xmin', 'xmax']) - if 'scale' in G_kwds: - kwds['scale'] = G_kwds['scale'] # pass down so plot knows if log-scale + kwds['scale'] = G_kwds['scale'] # pass scaling information to _plot too original_opts = kwds.pop('__original_opts', {}) do_show = kwds.pop('show',False) @@ -2108,12 +2105,6 @@ def _plot(funcs, xrange, parametric=False, else: f = funcs - #check to see if this is a log scale graph on the x axis - exp_points = False - if ('scale' in options.keys() and not parametric and - (options['scale'] == 'loglog' or options['scale'] == 'semilogx')): - exp_points = True - # Keep ``rgbcolor`` option 'automatic' only for lists of functions. # Otherwise, let the plot color be 'blue'. if parametric or not isinstance(funcs, (list, tuple)): @@ -2259,6 +2250,7 @@ def golden_rainbow(i,lightness=0.4): plot_points = int(options.pop('plot_points')) exclude = options.pop('exclude') + initial_points = None if exclude is not None: from sage.symbolic.expression import Expression if isinstance(exclude, Expression) and exclude.is_relational(): @@ -2286,21 +2278,39 @@ def golden_rainbow(i,lightness=0.4): initial_points = reduce(lambda a,b: a+b, [[x - epsilon, x + epsilon] for x in excluded_points], []) - data = generate_plot_points(f, xrange, plot_points, - adaptive_tolerance, adaptive_recursion, - randomize, initial_points, exp_dist=exp_points) - else: - data = generate_plot_points(f, xrange, plot_points, - adaptive_tolerance, adaptive_recursion, - randomize, exp_dist=exp_points) - + + # If we are a log scale plot on the x axis, do a change of variables + # so we sample the range in log scale + is_log_scale = ('scale' in options.keys() and + not parametric and + options['scale'] in ['loglog', 'semilogx']) + if is_log_scale: + f_orig = f + xrange_orig = xrange + f = lambda x: f_orig(exp(x)) + xrange = (log(xrange_orig[0]), log(xrange_orig[1])) + if not initial_points is None: + initial_points = [log(x) for x in initial_points] + + data = generate_plot_points(f, xrange, plot_points, + adaptive_tolerance, adaptive_recursion, + randomize, initial_points) for i in range(len(data)-1): # If the difference between consecutive x-values is more than # 2 times the difference between two consecutive plot points, then # add an exclusion point. - if abs(data[i+1][0] - data[i][0]) > 2*abs(xmax - xmin)/plot_points: + if abs(data[i+1][0] - data[i][0]) > 2*abs(xrange[1] - xrange[0])/plot_points: excluded_points.append((data[i][0] + data[i+1][0])/2) + + # If we did a change in variables, undo it now + if is_log_scale: + f = f_orig + xrange = xrange_orig + for i in range(len(data)): + data[i] = (exp(data[i][0]), data[i][1]) + for i in range(len(excluded_points)): + excluded_points[i] = exp(excluded_points[i]) if parametric: # We need the original x-values to be able to exclude points in parametric plots @@ -2345,7 +2355,7 @@ def golden_rainbow(i,lightness=0.4): fill_f = fill filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, \ - adaptive_recursion, randomize, exp_dist=exp_points) + adaptive_recursion, randomize) filldata.reverse() filldata += data else: @@ -2356,7 +2366,7 @@ def golden_rainbow(i,lightness=0.4): if not hasattr(fill, '__call__') and polar: filldata = generate_plot_points(lambda x: base_level, xrange, plot_points, adaptive_tolerance, \ - adaptive_recursion, randomize, exp_dist=exp_points) + adaptive_recursion, randomize) filldata.reverse() filldata += data if not hasattr(fill, '__call__') and not polar: @@ -3135,6 +3145,20 @@ def plot_semilogx(funcs, *args, **kwds): g = plot_semilogx(exp, (1,10), base=2) # with base 2 sphinx_plot(g) + :: + + sage: s = var('s') # Samples points logarithmically so graph is smooth + sage: f = 4000000/(4000000 + 4000*s*i - s*s) + sage: plot_semilogx(20*log(abs(f), 10), (s, 1, 1e6)) + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + + s = var('s') # Samples points logarithmically so graph is smooth + f = 4000000/(4000000 + 4000*s*i - s*s) + g = plot_semilogx(20*log(abs(f), 10), (s, 1, 1e6)) + sphinx_plot(g) + """ return plot(funcs, *args, scale='semilogx', **kwds) @@ -3805,7 +3829,7 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=5 return [] -def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize=True, initial_points=None, exp_dist=False): +def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize=True, initial_points=None): r""" Calculate plot points for a function f in the interval xrange. The adaptive refinement algorithm is also automatically invoked with a @@ -3833,9 +3857,6 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap - ``initial_points`` - (default: None) a list of points that should be evaluated. - - ``exp_dist`` - (default: False) whether points should be distributed linearly - (False) or exponentially (True) within the range specified - OUTPUT: - a list of points (x, f(x)) in the interval xrange, which approximate @@ -3885,16 +3906,6 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap [97, 499, 2681] """ from sage.plot.misc import setup_for_eval_on_grid - - f_actual = f - xrange_actual = xrange - if exp_dist: - if xrange[0] <= 0: - sage.misc.misc.verbose("Unable to perform exponential scale on negative range, clipping...", 1) - xrange[0] = 0.01 - f = lambda x: f_actual(exp(x)) - xrange = (log(xrange[0]), log(xrange[1])) - ignore, ranges = setup_for_eval_on_grid([], [xrange], plot_points) xmin, xmax, delta = ranges[0] data = srange(*ranges[0], include_endpoint=True) @@ -3984,8 +3995,4 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adap sage.misc.misc.verbose("WARNING: When plotting, failed to evaluate function at %s points." % exceptions, level=0) sage.misc.misc.verbose("Last error message: '%s'" % msg, level=0) - if exp_dist: - for i in range(len(data)): - data[i] = (exp(data[i][0]), data[i][1]) - return data From 0641da5c42bba02b4b75994e04d51b035be61fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 3 May 2020 17:52:23 +0200 Subject: [PATCH 156/476] spring cleanup of finite state machines (pep, lgtm, doc and code details) --- src/sage/combinat/finite_state_machine.py | 861 ++++++++-------------- 1 file changed, 308 insertions(+), 553 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 2e5c8d98847..61ebd590769 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -931,8 +931,7 @@ # **************************************************************************** from __future__ import print_function -import six -from six.moves import range, zip_longest, zip +from six.moves import zip_longest from IPython.lib.pretty import pretty import collections @@ -948,6 +947,7 @@ from sage.misc.misc import verbose from sage.misc.sageinspect import sage_getargspec from sage.rings.qqbar import QQbar +from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.structure.sage_object import SageObject @@ -1064,13 +1064,13 @@ def equal(iterator): return True -def startswith(list, prefix): +def startswith(list_, prefix): """ Determine whether list starts with the given prefix. INPUT: - - ``list`` -- list + - ``list_`` -- list - ``prefix`` -- list representing the prefix OUTPUT: @@ -1089,10 +1089,11 @@ def startswith(list, prefix): sage: startswith([1, 3, 2], [1, 2]) False """ + if len(prefix) > len(list_): + return False + return all(x == y for x, y in zip(list_, prefix)) - return list[:len(prefix)] == prefix - -#***************************************************************************** +# **************************************************************************** FSMEmptyWordSymbol = '-' @@ -1106,7 +1107,7 @@ def startswith(list, prefix): def FSMLetterSymbol(letter): """ - Returns a string associated to the input letter. + Return a string associated to the input letter. INPUT: @@ -1132,7 +1133,7 @@ def FSMLetterSymbol(letter): def FSMWordSymbol(word): """ - Returns a string of ``word``. It may returns the symbol of the + Return a string of ``word``. It may returns the symbol of the empty word ``FSMEmptyWordSymbol``. INPUT: @@ -1151,15 +1152,12 @@ def FSMWordSymbol(word): """ if not isinstance(word, list): return FSMLetterSymbol(word) - if len(word) == 0: + if not word: return FSMEmptyWordSymbol - s = '' - for letter in word: - s += (',' if len(s) > 0 else '') + FSMLetterSymbol(letter) - return s + return ','.join(FSMLetterSymbol(letter) for letter in word) -#***************************************************************************** +# **************************************************************************** def is_FSMState(S): @@ -1222,7 +1220,7 @@ class FSMState(SageObject): OUTPUT: - Returns a state of a finite state machine. + A state of a finite state machine. EXAMPLES:: @@ -1431,8 +1429,7 @@ def __init__(self, label, word_out=None, def __lt__(self, other): """ - Returns True if label of ``self`` is less than label of - ``other``. + Return ``True`` if label of ``self`` is less than label of ``other``. INPUT: @@ -1440,7 +1437,7 @@ def __lt__(self, other): OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -1450,7 +1447,6 @@ def __lt__(self, other): """ return self.label() < other.label() - @property def final_word_out(self): """ @@ -1643,10 +1639,9 @@ def is_final(self, is_final): "can have a final output word. " % (self.label(),)) - def label(self): """ - Returns the label of the state. + Return the label of the state. INPUT: @@ -1665,10 +1660,9 @@ def label(self): """ return self._label_ - def __copy__(self): """ - Returns a (shallow) copy of the state. + Return a (shallow) copy of the state. INPUT: @@ -1712,13 +1706,11 @@ def __copy__(self): new.hook = self.hook return new - copy = __copy__ - def __deepcopy__(self, memo): """ - Returns a deep copy of the state. + Return a deep copy of the state. INPUT: @@ -1748,10 +1740,9 @@ def __deepcopy__(self, memo): new.initial_probability = deepcopy(self.initial_probability, memo) return new - def deepcopy(self, memo=None): """ - Returns a deep copy of the state. + Return a deep copy of the state. INPUT: @@ -1796,7 +1787,7 @@ def deepcopy(self, memo=None): def relabeled(self, label, memo=None): """ - Returns a deep copy of the state with a new label. + Return a deep copy of the state with a new label. INPUT: @@ -1870,11 +1861,7 @@ def __getstate__(self): def __hash__(self): """ - Returns a hash value for the object. - - INPUT: - - Nothing. + Return a hash value for the object. OUTPUT: @@ -1910,20 +1897,20 @@ def _repr_(self): """ return pretty(self.label()) - def __eq__(left, right): + def __eq__(self, other): """ - Returns True if two states are the same, i.e., if they have + Return ``True`` if two states are the same, i.e., if they have the same labels. INPUT: - - ``left`` -- a state. + - ``self`` -- a state. - - ``right`` -- a state. + - ``other`` -- a state. OUTPUT: - True or False. + ``True`` or ``False``. Note that the hooks and whether the states are initial or final are not checked. To fully compare two states (including @@ -1943,24 +1930,23 @@ def __eq__(left, right): sage: A == B True """ - if not is_FSMState(right): + if not is_FSMState(other): return False - return left.label() == right.label() - + return self.label() == other.label() - def __ne__(left, right): + def __ne__(self, other): """ Tests for inequality, complement of __eq__. INPUT: - - ``left`` -- a state. + - ``self`` -- a state. - - ``right`` -- a state. + - ``other`` -- a state. OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -1970,19 +1956,18 @@ def __ne__(left, right): sage: A != B False """ - return (not (left == right)) + return not (self == other) - - def fully_equal(left, right, compare_color=True): + def fully_equal(self, other, compare_color=True): """ - Checks whether two states are fully equal, i.e., including all + Check whether two states are fully equal, i.e., including all attributes except ``hook``. INPUT: - - ``left`` -- a state. + - ``self`` -- a state. - - ``right`` -- a state. + - ``other`` -- a state. - ``compare_color`` -- If ``True`` (default) colors are compared as well, otherwise not. @@ -2008,27 +1993,18 @@ def fully_equal(left, right, compare_color=True): sage: A.fully_equal(B, compare_color=False) True """ - color = not compare_color or left.color == right.color - return (left == right and - left.is_initial == right.is_initial and - left.is_final == right.is_final and - left.final_word_out == right.final_word_out and - left.word_out == right.word_out and + color = not compare_color or self.color == other.color + return (self == other and + self.is_initial == other.is_initial and + self.is_final == other.is_final and + self.final_word_out == other.final_word_out and + self.word_out == other.word_out and color and - left.initial_probability == right.initial_probability) - + self.initial_probability == other.initial_probability) def __bool__(self): """ - Returns True. - - INPUT: - - Nothing. - - OUTPUT: - - True or False. + Return ``True``. TESTS:: @@ -2038,13 +2014,11 @@ def __bool__(self): """ return True # A state cannot be zero (see __init__) - __nonzero__ = __bool__ - def _epsilon_successors_(self, fsm=None): """ - Returns the dictionary with states reachable from ``self`` + Return the dictionary with states reachable from ``self`` without reading anything from an input tape as keys. The values are lists of outputs. @@ -2105,15 +2079,14 @@ def _epsilon_successors_(self, fsm=None): _epsilon_successors_dict_[self].remove([]) # delete starting state if not _epsilon_successors_dict_[self]: del _epsilon_successors_dict_[self] - for s, outputs in six.iteritems(_epsilon_successors_dict_): + for s, outputs in _epsilon_successors_dict_.items(): _epsilon_successors_dict_[s] = [t for t, _ in itertools.groupby(sorted(outputs))] return _epsilon_successors_dict_ - def _in_epsilon_cycle_(self, fsm=None): """ - Returns whether ``self`` is in an epsilon-cycle or not. + Return whether ``self`` is in an epsilon-cycle or not. INPUT: @@ -2140,10 +2113,9 @@ def _in_epsilon_cycle_(self, fsm=None): """ return self in self._epsilon_successors_(fsm) - def _epsilon_cycle_output_empty_(self, fsm=None): """ - Returns whether all epsilon-cycles in which ``self`` is + Return whether all epsilon-cycles in which ``self`` is contained have an empty output (i.e., do not write any output word). @@ -2154,7 +2126,7 @@ def _epsilon_cycle_output_empty_(self, fsm=None): OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` A ``ValueError`` is raised when ``self`` is not in an epsilon cycle. @@ -2203,7 +2175,7 @@ def _epsilon_cycle_output_empty_(self, fsm=None): raise ValueError("State %s is not in an epsilon cycle." % (self,)) -#***************************************************************************** +# **************************************************************************** def is_FSMTransition(T): @@ -2311,16 +2283,16 @@ def __init__(self, from_state, to_state, def __lt__(self, other): """ - Returns True if ``self`` is less than ``other`` with respect to the + Return True if ``self`` is less than ``other`` with respect to the key ``(self.from_state, self.word_in, self.to_state, self.word_out)``. INPUT: - - `other` -- a transition. + - ``other`` -- a transition. OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -2331,14 +2303,9 @@ def __lt__(self, other): return (self.from_state, self.word_in, self.to_state, self.word_out) < \ (other.from_state, other.word_in, other.to_state, other.word_out) - def __copy__(self): """ - Returns a (shallow) copy of the transition. - - INPUT: - - Nothing. + Return a (shallow) copy of the transition. OUTPUT: @@ -2357,13 +2324,11 @@ def __copy__(self): new.hook = self.hook return new - copy = __copy__ - def __deepcopy__(self, memo): """ - Returns a deep copy of the transition. + Return a deep copy of the transition. INPUT: @@ -2388,10 +2353,9 @@ def __deepcopy__(self, memo): new.hook = deepcopy(self.hook, memo) return new - def deepcopy(self, memo=None): """ - Returns a deep copy of the transition. + Return a deep copy of the transition. INPUT: @@ -2437,11 +2401,9 @@ def _repr_(self): repr(self.to_state), self._in_out_label_()) - def _in_out_label_(self): """ - Returns the input and output of a transition as - "word_in|word_out". + Return the input and output of a transition as "word_in|word_out". INPUT: @@ -2460,10 +2422,9 @@ def _in_out_label_(self): return "%s|%s" % (FSMWordSymbol(self.word_in), FSMWordSymbol(self.word_out)) - - def __eq__(left, right): + def __eq__(self, other): """ - Returns True if the two transitions are the same, i.e., if the + Return ``True`` if the two transitions are the same, i.e., if the both go from the same states to the same states and read and write the same words. @@ -2471,13 +2432,13 @@ def __eq__(left, right): INPUT: - - ``left`` -- a transition. + - ``self`` -- a transition. - - ``right`` -- a transition. + - ``other`` -- a transition. OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -2488,28 +2449,27 @@ def __eq__(left, right): sage: t1 == t2 True """ - if not is_FSMTransition(right): - raise TypeError('Only instances of FSMTransition ' \ - 'can be compared.') - return left.from_state == right.from_state \ - and left.to_state == right.to_state \ - and left.word_in == right.word_in \ - and left.word_out == right.word_out - + if not is_FSMTransition(other): + raise TypeError('Only instances of FSMTransition ' + 'can be compared.') + return self.from_state == other.from_state \ + and self.to_state == other.to_state \ + and self.word_in == other.word_in \ + and self.word_out == other.word_out - def __ne__(left, right): + def __ne__(self, other): """ + Test for inequality, complement of __eq__. INPUT: - - ``left`` -- a transition. + - ``self`` -- a transition. - - ``right`` -- a transition. + - ``other`` -- a transition. OUTPUT: - True or False. - Tests for inequality, complement of __eq__. + ``True`` or ``False`` EXAMPLES:: @@ -2520,20 +2480,11 @@ def __ne__(left, right): sage: t1 != t2 False """ - return (not (left == right)) - + return not (self == other) def __bool__(self): """ - Returns True. - - INPUT: - - Nothing. - - OUTPUT: - - True or False. + Return ``True``. EXAMPLES:: @@ -2546,7 +2497,7 @@ def __bool__(self): __nonzero__ = __bool__ -#***************************************************************************** +# **************************************************************************** def is_FiniteStateMachine(FSM): @@ -3126,9 +3077,9 @@ class FiniteStateMachine(SageObject): :attr:`input_alphabet`. """ - #************************************************************************* + # ************************************************************************ # init - #************************************************************************* + # ************************************************************************ def __init__(self, @@ -3147,9 +3098,10 @@ def __init__(self, sage: FiniteStateMachine() Empty finite state machine """ - self._states_ = [] # List of states in the finite state - # machine. Each state stores a list of - # outgoing transitions. + self._states_ = [] + # List of states in the finite state + # machine. Each state stores a list of + # outgoing transitions. if store_states_dict: self._states_dict_ = {} @@ -3191,16 +3143,16 @@ def __init__(self, if initial_states is not None: if not hasattr(initial_states, '__iter__'): - raise TypeError('Initial states must be iterable ' \ - '(e.g. a list of states).') + raise TypeError('Initial states must be iterable ' + '(e.g. a list of states).') for s in initial_states: state = self.add_state(s) state.is_initial = True if final_states is not None: if not hasattr(final_states, '__iter__'): - raise TypeError('Final states must be iterable ' \ - '(e.g. a list of states).') + raise TypeError('Final states must be iterable ' + '(e.g. a list of states).') for s in final_states: state = self.add_state(s) state.is_final = True @@ -3211,7 +3163,7 @@ def __init__(self, if on_duplicate_transition is None: on_duplicate_transition = duplicate_transition_ignore if hasattr(on_duplicate_transition, '__call__'): - self.on_duplicate_transition=on_duplicate_transition + self.on_duplicate_transition = on_duplicate_transition else: raise TypeError('on_duplicate_transition must be callable') @@ -3220,10 +3172,10 @@ def __init__(self, elif hasattr(data, 'items'): # data is a dict (or something similar), # format: key = from_state, value = iterator of transitions - for (sf, iter_transitions) in six.iteritems(data): + for (sf, iter_transitions) in data.items(): self.add_state(sf) if hasattr(iter_transitions, 'items'): - for (st, transition) in six.iteritems(iter_transitions): + for (st, transition) in iter_transitions.items(): self.add_state(st) if is_FSMTransition(transition): self.add_transition(transition) @@ -3274,18 +3226,13 @@ def __init__(self, self.construct_final_word_out(with_final_word_out) - #************************************************************************* + # ************************************************************************ # copy and hash - #************************************************************************* - + # ************************************************************************ def __copy__(self): """ - Returns a (shallow) copy of the finite state machine. - - INPUT: - - Nothing. + Return a (shallow) copy of the finite state machine. OUTPUT: @@ -3300,13 +3247,11 @@ def __copy__(self): """ raise NotImplementedError - copy = __copy__ - def empty_copy(self, memo=None, new_class=None): """ - Returns an empty deep copy of the finite state machine, i.e., + Return an empty deep copy of the finite state machine, i.e., ``input_alphabet``, ``output_alphabet``, ``on_duplicate_transition`` are preserved, but states and transitions are not. @@ -3352,10 +3297,9 @@ def empty_copy(self, memo=None, new_class=None): new._copy_from_other_(self, memo=memo, empty=True) return new - def __deepcopy__(self, memo): """ - Returns a deep copy of the finite state machine. + Return a deep copy of the finite state machine. INPUT: @@ -3375,10 +3319,9 @@ def __deepcopy__(self, memo): new._copy_from_other_(self) return new - def deepcopy(self, memo=None): """ - Returns a deep copy of the finite state machine. + Return a deep copy of the finite state machine. INPUT: @@ -3463,10 +3406,6 @@ def __getstate__(self): """ Return state for pickling excluding outgoing transitions. - INPUT: - - None - OUTPUT: A dictionary. @@ -3481,10 +3420,8 @@ def __getstate__(self): sage: loads(dumps(A)) == A True """ - odict = self.__dict__.copy() # copy the dict since we change it - odict.update({ - 'transitions': self.transitions() - }) + odict = self.__dict__.copy() # copy the dict since we change it + odict.update({'transitions': self.transitions()}) return odict def __setstate__(self, d): @@ -3512,13 +3449,13 @@ def __setstate__(self, d): transitions = d.pop('transitions') self.__dict__.update(d) for state in self.iter_states(): - state.transitions = [] # clean outgoing transitions + state.transitions = [] # clean outgoing transitions for transition in transitions: self.add_transition(transition) def relabeled(self, memo=None, labels=None): """ - Returns a deep copy of the finite state machine, but the + Return a deep copy of the finite state machine, but the states are relabeled. INPUT: @@ -3563,10 +3500,9 @@ def relabeled(self, memo=None, labels=None): del self._deepcopy_labels_ return new - def induced_sub_finite_state_machine(self, states): """ - Returns a sub-finite-state-machine of the finite state machine + Return a sub-finite-state-machine of the finite state machine induced by the given states. INPUT: @@ -3644,13 +3580,13 @@ def __hash__(self): """ if getattr(self, "_immutable", False): return hash((tuple(self.states()), tuple(self.transitions()))) - raise TypeError("Finite state machines are mutable, " \ - "and thus not hashable.") + raise TypeError("Finite state machines are mutable, " + "and thus not hashable.") - #************************************************************************* + # ************************************************************************ # operators - #************************************************************************* + # ************************************************************************ def __or__(self, other): @@ -3701,10 +3637,9 @@ def __iadd__(self, other): """ raise NotImplementedError - def __and__(self, other): """ - Returns the intersection of ``self`` with ``other``. + Return the intersection of ``self`` with ``other``. TESTS:: @@ -3716,7 +3651,6 @@ def __and__(self, other): if is_FiniteStateMachine(other): return self.intersection(other) - def __imul__(self, other): """ TESTS:: @@ -3962,41 +3896,34 @@ def __call__(self, *args, **kwargs): ....: automatic_output_type=True)) <... 'tuple'> """ - if len(args) == 0: + if not args: raise TypeError("Called with too few arguments.") if is_FiniteStateMachine(args[0]): return self.composition(*args, **kwargs) if hasattr(args[0], '__iter__'): - if not 'full_output' in kwargs: + if 'full_output' not in kwargs: kwargs['full_output'] = False - if not 'list_of_outputs' in kwargs: + if 'list_of_outputs' not in kwargs: kwargs['list_of_outputs'] = False - if not 'automatic_output_type' in kwargs: - kwargs['automatic_output_type'] = not 'format_output' in kwargs + if 'automatic_output_type' not in kwargs: + kwargs['automatic_output_type'] = 'format_output' not in kwargs input_tape = args[0] - if hasattr(input_tape, 'is_finite') and \ - not input_tape.is_finite(): - if not 'iterator_type' in kwargs: + if hasattr(input_tape, 'is_finite') and not input_tape.is_finite(): + if 'iterator_type' not in kwargs: kwargs['iterator_type'] = 'simple' return self.iter_process(*args, **kwargs) return self.process(*args, **kwargs) raise TypeError("Do not know what to do with that arguments.") - - #************************************************************************* + # ************************************************************************ # tests - #************************************************************************* - + # ************************************************************************ def __bool__(self): """ - Returns True if the finite state machine consists of at least + Return True if the finite state machine consists of at least one state. - INPUT: - - Nothing. - OUTPUT: True or False. @@ -4010,16 +3937,16 @@ def __bool__(self): __nonzero__ = __bool__ - def __eq__(left, right): + def __eq__(self, other): """ - Returns ``True`` if the two finite state machines are equal, + Return ``True`` if the two finite state machines are equal, i.e., if they have the same states and the same transitions. INPUT: - - ``left`` -- a finite state machine. + - ``self`` -- a finite state machine. - - ``right`` -- a finite state machine. + - ``other`` -- a finite state machine. OUTPUT: @@ -4063,53 +3990,50 @@ def __eq__(left, right): sage: F == G True """ - if not is_FiniteStateMachine(right): + if not is_FiniteStateMachine(other): raise TypeError('Only instances of FiniteStateMachine ' - 'can be compared.') - if len(left._states_) != len(right._states_): + 'can be compared.') + if len(self._states_) != len(other._states_): return False colors_equal = True - for state in left.iter_states(): + for state in self.iter_states(): try: - right_state = right.state(state.label()) + other_state = other.state(state.label()) except LookupError: return False # we handle colors separately - if not state.fully_equal(right_state, compare_color=False): + if not state.fully_equal(other_state, compare_color=False): return False - if state.color != right_state.color: + if state.color != other_state.color: colors_equal = False - left_transitions = state.transitions - right_transitions = right.state(state).transitions - if len(left_transitions) != len(right_transitions): + self_transitions = state.transitions + other_transitions = other.state(state).transitions + if len(self_transitions) != len(other_transitions): return False - for t in left_transitions: - if t not in right_transitions: + for t in self_transitions: + if t not in other_transitions: return False # handle colors if colors_equal: return True - if left.is_monochromatic() and right.is_monochromatic(): - return True - return False + return self.is_monochromatic() and other.is_monochromatic() - - def __ne__(left, right): + def __ne__(self, other): """ Tests for inequality, complement of :meth:`.__eq__`. INPUT: - - ``left`` -- a finite state machine. + - ``self`` -- a finite state machine. - - ``right`` -- a finite state machine. + - ``other`` -- a finite state machine. OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -4121,13 +4045,14 @@ def __ne__(left, right): sage: E == G False """ - return (not (left == right)) - + return not (self == other) def __contains__(self, item): """ - Returns true, if the finite state machine contains the - state or transition item. Note that only the labels of the + Return ``True``, if the finite state machine contains the + state or transition item. + + Note that only the labels of the states and the input and output words are tested. INPUT: @@ -4136,7 +4061,7 @@ def __contains__(self, item): OUTPUT: - True or False. + ``True`` or ``False`` EXAMPLES:: @@ -4274,9 +4199,9 @@ def default_is_zero(expression): for state in self.iter_states()) - #************************************************************************* + # ************************************************************************ # representations / LaTeX - #************************************************************************* + # ************************************************************************ def _repr_(self): @@ -4349,7 +4274,6 @@ def format_letter_negative(self, letter): \path[->] (v0) edge[loop above] node {$\overline{1}$} (); \end{tikzpicture} """ - from sage.rings.integer_ring import ZZ if letter in ZZ and letter < 0: return r'\overline{%d}' % -letter else: @@ -4855,11 +4779,7 @@ def latex_options(self, def _latex_(self): r""" - Returns a LaTeX code for the graph of the finite state machine. - - INPUT: - - Nothing. + Return a LaTeX code for the graph of the finite state machine. OUTPUT: @@ -4956,7 +4876,7 @@ def label_rotation(angle, both_directions): accepting_show_empty = False result = "\\begin{tikzpicture}[%s]\n" % ", ".join(options) - j = 0; + j = 0 for vertex in self.iter_states(): if not hasattr(vertex, "coordinates"): vertex.coordinates = (3*cos(2*pi*j/len(self.states())), @@ -5008,24 +4928,20 @@ def key_function(s): # transitions have to be sorted anyway, the performance # penalty should be bearable; nevertheless, this is only # required for doctests. - adjacent = collections.OrderedDict( - (pair, list(transitions)) - for pair, transitions in - itertools.groupby( - sorted(self.iter_transitions(), - key=key_function), - key=key_function - )) - - for ((source, target), transitions) in six.iteritems(adjacent): - if len(transitions) > 0: + adjacent = collections.OrderedDict((pair, list(transitions)) + for pair, transitions in itertools.groupby( + sorted(self.iter_transitions(), key=key_function), + key=key_function)) + + for ((source, target), transitions) in adjacent.items(): + if transitions: labels = [] for transition in transitions: if hasattr(transition, "format_label"): labels.append(transition.format_label()) else: labels.append(self._latex_transition_label_( - transition, self.format_transition_label)) + transition, self.format_transition_label)) label = ", ".join(labels) if source != target: angle = atan2( @@ -5057,17 +4973,16 @@ def key_function(s): result += "\\end{tikzpicture}" return result - def _latex_transition_label_(self, transition, format_function=None): r""" - Returns the proper transition label. + Return the proper transition label. INPUT: - - ``transition`` - a transition + - ``transition`` -- a transition - - ``format_function`` - a function formatting the labels + - ``format_function`` -- a function formatting the labels OUTPUT: @@ -5140,15 +5055,14 @@ def set_coordinates(self, coordinates, default=True): state.coordinates = (3*cos(2*pi*j/n), 3*sin(2*pi*j/n)) - - #************************************************************************* + # ************************************************************************ # other - #************************************************************************* - + # ************************************************************************ def _matrix_(self, R=None): """ - Returns the adjacency matrix of the finite state machine. + Return the adjacency matrix of the finite state machine. + See :meth:`.adjacency_matrix` for more information. EXAMPLES:: @@ -5168,11 +5082,10 @@ def _matrix_(self, R=None): """ return self.adjacency_matrix() - def adjacency_matrix(self, input=None, entry=None): """ - Returns the adjacency matrix of the underlying graph. + Return the adjacency matrix of the underlying graph. INPUT: @@ -5245,7 +5158,6 @@ def adjacency_matrix(self, input=None, [1 1 0] """ - from sage.rings.integer_ring import ZZ def default_function(transitions): x = var('x') @@ -5326,7 +5238,6 @@ def determine_input_alphabet(self, reset=True): ain.add(letter) self.input_alphabet = list(ain) - def determine_output_alphabet(self, reset=True): """ Determine the output alphabet according to the transitions @@ -5380,7 +5291,6 @@ def determine_output_alphabet(self, reset=True): aout.add(letter) self.output_alphabet = list(aout) - def determine_alphabets(self, reset=True): """ Determine the input and output alphabet according to the @@ -5424,19 +5334,13 @@ def determine_alphabets(self, reset=True): self.determine_input_alphabet(reset) self.determine_output_alphabet(reset) - - #************************************************************************* + # ************************************************************************ # get states and transitions - #************************************************************************* - + # ************************************************************************ def states(self): """ - Returns the states of the finite state machine. - - INPUT: - - Nothing. + Return the states of the finite state machine. OUTPUT: @@ -5452,11 +5356,7 @@ def states(self): def iter_states(self): """ - Returns an iterator of the states. - - INPUT: - - Nothing. + Return an iterator of the states. OUTPUT: @@ -5470,10 +5370,9 @@ def iter_states(self): """ return iter(self._states_) - def transitions(self, from_state=None): """ - Returns a list of all transitions. + Return a list of all transitions. INPUT: @@ -5493,10 +5392,9 @@ def transitions(self, from_state=None): """ return list(self.iter_transitions(from_state)) - def iter_transitions(self, from_state=None): """ - Returns an iterator of all transitions. + Return an iterator of all transitions. INPUT: @@ -5525,14 +5423,9 @@ def iter_transitions(self, from_state=None): else: return iter(self.state(from_state).transitions) - def _iter_transitions_all_(self): """ - Returns an iterator over all transitions. - - INPUT: - - Nothing. + Return an iterator over all transitions. OUTPUT: @@ -5549,14 +5442,9 @@ def _iter_transitions_all_(self): for t in state.transitions: yield t - def initial_states(self): """ - Returns a list of all initial states. - - INPUT: - - Nothing. + Return a list of all initial states. OUTPUT: @@ -5573,14 +5461,9 @@ def initial_states(self): """ return list(self.iter_initial_states()) - def iter_initial_states(self): """ - Returns an iterator of the initial states. - - INPUT: - - Nothing. + Return an iterator of the initial states. OUTPUT: @@ -5599,11 +5482,7 @@ def iter_initial_states(self): def final_states(self): """ - Returns a list of all final states. - - INPUT: - - Nothing. + Return a list of all final states. OUTPUT: @@ -5621,14 +5500,9 @@ def final_states(self): """ return list(self.iter_final_states()) - def iter_final_states(self): """ - Returns an iterator of the final states. - - INPUT: - - Nothing. + Return an iterator of the final states. OUTPUT: @@ -5648,7 +5522,7 @@ def iter_final_states(self): def state(self, state): """ - Returns the state of the finite state machine. + Return the state of the finite state machine. INPUT: @@ -5658,8 +5532,7 @@ def state(self, state): OUTPUT: - Returns the state of the finite state machine corresponding to - ``state``. + The state of the finite state machine corresponding to ``state``. If no state is found, then a ``LookupError`` is thrown. @@ -5692,10 +5565,9 @@ def what(s, switch): pass raise LookupError("No state with label %s found." % (what(state, switch),)) - def transition(self, transition): """ - Returns the transition of the finite state machine. + Return the transition of the finite state machine. INPUT: @@ -5705,8 +5577,8 @@ def transition(self, transition): OUTPUT: - Returns the transition of the finite state machine - corresponding to ``transition``. + The transition of the finite state machine corresponding + to ``transition``. If no transition is found, then a ``LookupError`` is thrown. @@ -5727,15 +5599,13 @@ def transition(self, transition): return s raise LookupError("No transition found.") - - #************************************************************************* + # ************************************************************************ # properties (state and transitions) - #************************************************************************* - + # ************************************************************************ def has_state(self, state): """ - Returns whether ``state`` is one of the states of the finite + Return whether ``state`` is one of the states of the finite state machine. INPUT: @@ -5757,10 +5627,9 @@ def has_state(self, state): except LookupError: return False - def has_transition(self, transition): """ - Returns whether ``transition`` is one of the transitions of + Return whether ``transition`` is one of the transitions of the finite state machine. INPUT: @@ -5786,10 +5655,9 @@ def has_transition(self, transition): return transition in self.iter_transitions() raise TypeError("Transition is not an instance of FSMTransition.") - def has_initial_state(self, state): """ - Returns whether ``state`` is one of the initial states of the + Return whether ``state`` is one of the initial states of the finite state machine. INPUT: @@ -5811,14 +5679,9 @@ def has_initial_state(self, state): except LookupError: return False - def has_initial_states(self): """ - Returns whether the finite state machine has an initial state. - - INPUT: - - Nothing. + Return whether the finite state machine has an initial state. OUTPUT: @@ -5829,12 +5692,11 @@ def has_initial_states(self): sage: FiniteStateMachine().has_initial_states() False """ - return len(self.initial_states()) > 0 - + return bool(self.initial_states()) def has_final_state(self, state): """ - Returns whether ``state`` is one of the final states of the + Return whether ``state`` is one of the final states of the finite state machine. INPUT: @@ -5855,14 +5717,9 @@ def has_final_state(self, state): except LookupError: return False - def has_final_states(self): """ - Returns whether the finite state machine has a final state. - - INPUT: - - Nothing. + Return whether the finite state machine has a final state. OUTPUT: @@ -5873,25 +5730,19 @@ def has_final_states(self): sage: FiniteStateMachine().has_final_states() False """ - return len(self.final_states()) > 0 - + return bool(self.final_states()) - #************************************************************************* + # ************************************************************************ # properties - #************************************************************************* - + # ************************************************************************ def is_deterministic(self): """ Return whether the finite finite state machine is deterministic. - INPUT: - - Nothing. - OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` A finite state machine is considered to be deterministic if each transition has input label of length one and for each @@ -5925,7 +5776,7 @@ def is_deterministic(self): sage: Automaton(initial_states=[0, 1]).is_deterministic() False """ - if len(self.initial_states())>1: + if len(self.initial_states()) > 1: return False for state in self.iter_states(): for transition in state.transitions: @@ -5936,23 +5787,18 @@ def is_deterministic(self): state.transitions, key=lambda t: t.word_in) - for key,transition_class in transition_classes_by_word_in: + for key, transition_class in transition_classes_by_word_in: if len(transition_class) > 1: return False return True - def is_complete(self): """ - Returns whether the finite state machine is complete. - - INPUT: - - Nothing. + Return whether the finite state machine is complete. OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` A finite state machine is considered to be complete if each transition has an input label of length one and for each @@ -6020,9 +5866,9 @@ def is_connected(self): raise NotImplementedError - #************************************************************************* + # ************************************************************************ # let the finite state machine work - #************************************************************************* + # ************************************************************************ _process_default_options_ = {'full_output': True, 'list_of_outputs': None, @@ -6030,10 +5876,9 @@ def is_connected(self): 'always_include_output': False, 'automatic_output_type': False} - def process(self, *args, **kwargs): """ - Returns whether the finite state machine accepts the input, the state + Return whether the finite state machine accepts the input, the state where the computation stops and which output is generated. INPUT: @@ -6638,14 +6483,14 @@ def _iter_process_simple_(self, iterator): "'simple' iterator cannot be used " "here." % (len(current),)) - pos, states = next(six.iteritems(current)) + pos, states = next(iter(current.items())) if len(states) > 1: raise RuntimeError("Process has branched " "(visiting %s states in branch). The " "'simple' iterator cannot be used " "here." % (len(states),)) - state, branch = next(six.iteritems(states)) + state, branch = next(iter(states.items())) if len(branch.outputs) > 1: raise RuntimeError("Process has branched. " "(%s different outputs in branch). The " @@ -6655,15 +6500,14 @@ def _iter_process_simple_(self, iterator): for o in branch.outputs[0]: yield o - branch.outputs[0] = [] # Reset output so that in the next round - # (of "for current in iterator") only new - # output is returned (by the yield). - + branch.outputs[0] = [] + # Reset output so that in the next round + # (of "for current in iterator") only new + # output is returned (by the yield). - #************************************************************************* + # ************************************************************************ # change finite state machine (add/remove state/transitions) - #************************************************************************* - + # ************************************************************************ def add_state(self, state): """ @@ -6959,9 +6803,9 @@ def add_from_transition_function(self, function, initial_states=None, state.is_initial = True not_done.append(state) else: - raise TypeError('Initial states must be iterable ' \ - '(e.g. a list of states).') - if len(not_done) == 0: + raise TypeError('Initial states must be iterable ' + '(e.g. a list of states).') + if not not_done: raise ValueError("No state is initial.") if explore_existing_states: ignore_done = self.states() @@ -6996,7 +6840,7 @@ def add_from_transition_function(self, function, initial_states=None, for (st_label, word) in return_value: if not self.has_state(st_label): not_done.append(self.add_state(st_label)) - elif len(ignore_done) > 0: + elif ignore_done: u = self.state(st_label) if u in ignore_done: not_done.append(u) @@ -7090,14 +6934,14 @@ def add_transitions_from_function(self, function, labels_as_input=True): transitions = return_value for t in transitions: if not hasattr(t, '__getitem__'): - raise ValueError("The callback function for " - "add_transitions_from_function " - "is expected to return a " - "pair (word_in, word_out) or a " - "list of such pairs. For " - "states %s and %s however, it " - "returned %s, which is not " - "acceptable." % (s_from, s_to, return_value)) + raise ValueError("The callback function for " + "add_transitions_from_function " + "is expected to return a " + "pair (word_in, word_out) or a " + "list of such pairs. For " + "states %s and %s however, it " + "returned %s, which is not " + "acceptable." % (s_from, s_to, return_value)) label_in = t[0] try: label_out = t[1] @@ -7183,10 +7027,9 @@ def remove_epsilon_transitions(self): """ raise NotImplementedError - def epsilon_successors(self, state): """ - Returns the dictionary with states reachable from ``state`` + Return the dictionary with states reachable from ``state`` without reading anything from an input tape as keys. The values are lists of outputs. @@ -7270,29 +7113,27 @@ def accessible_components(self): sage: F.accessible_components() Automaton with 3 states """ - - if len(self.initial_states()) == 0: + if not self.initial_states(): return deepcopy(self) - memo = {} + def accessible(from_state, read): return [(deepcopy(x.to_state, memo), x.word_out) for x in self.iter_transitions(from_state) if x.word_in[0] == read] - new_initial_states=[deepcopy(x, memo) for x in self.initial_states()] + new_initial_states = [deepcopy(x, memo) for x in self.initial_states()] result = self.empty_copy() result.add_from_transition_function(accessible, initial_states=new_initial_states) for final_state in self.iter_final_states(): try: - new_final_state=result.state(final_state.label) - new_final_state.is_final=True + new_final_state = result.state(final_state.label) + new_final_state.is_final = True except LookupError: pass return result - def coaccessible_components(self): r""" Return the sub-machine induced by the coaccessible states of this @@ -7813,7 +7654,7 @@ def product_FiniteStateMachine(self, other, function, final_function=None, new_class=None): r""" - Returns a new finite state machine whose states are + Return a new finite state machine whose states are `d`-tuples of states of the original finite state machines. INPUT: @@ -8080,7 +7921,7 @@ def default_final_function(*args): def composition(self, other, algorithm=None, only_accessible_components=True): """ - Returns a new transducer which is the composition of ``self`` + Return a new transducer which is the composition of ``self`` and ``other``. INPUT: @@ -8378,16 +8219,9 @@ def composition(self, other, algorithm=None, "possible.") if algorithm is None: - if (any(len(t.word_out) > 1 - for t in other.iter_transitions()) + if (any(len(t.word_out) > 1 for t in other.iter_transitions()) or - any(len(t.word_in) != 1 - for t in self.iter_transitions()) - #this might be used for multi-tape mode. - #or - #any(isinstance(t.word_in[0], tuple) and None in t.word_in[0] - # for t in self.iter_transitions()) - ): + any(len(t.word_in) != 1 for t in self.iter_transitions())): algorithm = 'explorative' else: algorithm = 'direct' @@ -8398,7 +8232,6 @@ def composition(self, other, algorithm=None, else: raise ValueError("Unknown algorithm %s." % (algorithm,)) - def _composition_direct_(self, other, only_accessible_components=True): """ See :meth:`.composition` for details. @@ -8544,16 +8377,11 @@ def composition_transition(states, input): F.output_alphabet = second.output_alphabet return F - def input_projection(self): """ - Returns an automaton where the output of each transition of + Return an automaton where the output of each transition of self is deleted. - INPUT: - - Nothing - OUTPUT: An automaton. @@ -8570,16 +8398,11 @@ def input_projection(self): """ return self.projection(what='input') - def output_projection(self): """ - Returns a automaton where the input of each transition of self + Return a automaton where the input of each transition of self is deleted and the new input is the original output. - INPUT: - - Nothing - OUTPUT: An automaton. @@ -8614,10 +8437,9 @@ def output_projection(self): """ return self.projection(what='output') - def projection(self, what='input'): """ - Returns an Automaton which transition labels are the projection + Return an Automaton which transition labels are the projection of the transition labels of the input. INPUT: @@ -8682,10 +8504,9 @@ def projection(self, what='input'): return new - def transposition(self, reverse_output_labels=True): """ - Returns a new finite state machine, where all transitions of the + Return a new finite state machine, where all transitions of the input finite state machine are reversed. INPUT: @@ -8784,17 +8605,12 @@ def transposition(self, reverse_output_labels=True): return transposition - def split_transitions(self): """ - Returns a new transducer, where all transitions in self with input + Return a new transducer, where all transitions in self with input labels consisting of more than one letter are replaced by a path of the corresponding length. - INPUT: - - Nothing. - OUTPUT: A new transducer. @@ -8825,16 +8641,11 @@ def split_transitions(self): transition.word_out)) return new - def final_components(self): """ - Returns the final components of a finite state machine as finite + Return the final components of a finite state machine as finite state machines. - INPUT: - - Nothing. - OUTPUT: A list of finite state machines, each representing a final @@ -9006,7 +8817,6 @@ def completion(self, sink=None): except LookupError: pass else: - from sage.rings.integer_ring import ZZ sink = 1 + max(itertools.chain( [-1], (s.label() for s in result.iter_states() @@ -9205,11 +9015,7 @@ def find_common_output(state): def equivalence_classes(self): r""" - Returns a list of equivalence classes of states. - - INPUT: - - Nothing. + Return a list of equivalence classes of states. OUTPUT: @@ -9283,7 +9089,7 @@ def equivalence_classes(self): state.final_word_out) states_grouped = full_group_by(self.states(), key=key_0) classes_current = [equivalence_class for - (key,equivalence_class) in states_grouped] + (key, equivalence_class) in states_grouped] while len(classes_current) != len(classes_previous): class_of = {} @@ -9303,15 +9109,13 @@ def equivalence_classes(self): for class_previous in classes_previous: states_grouped = full_group_by(class_previous, key=key_current) classes_current.extend([equivalence_class for - (key,equivalence_class) in states_grouped]) + (key, equivalence_class) in states_grouped]) return classes_current - def quotient(self, classes): r""" - Constructs the quotient with respect to the equivalence - classes. + Construct the quotient with respect to the equivalence classes. INPUT: @@ -9404,10 +9208,10 @@ def quotient(self, classes): for t in c[0].transitions]) for transition in self.iter_transitions(c[0]): new.add_transition( - from_state = new_state, - to_state = state_mapping[transition.to_state], - word_in = transition.word_in, - word_out = transition.word_out) + from_state=new_state, + to_state=state_mapping[transition.to_state], + word_in=transition.word_in, + word_out=transition.word_out) # check that all class members have the same information (modulo classes) for state in c: @@ -9477,7 +9281,7 @@ def key(transition): memo = {} for state in self.states(): - new_state = deepcopy(state,memo) + new_state = deepcopy(state, memo) state_dict[state] = new_state new.add_state(new_state) @@ -9882,20 +9686,18 @@ def find_final_word_out(state): # have been computed as it may not be permissible to stop at a # formerly non-final state unless a cycle has been completed. - for (state, position), final_word_out in six.iteritems(cache): + for (state, position), final_word_out in cache.items(): if position == 0 and final_word_out is not None: state.is_final = True state.final_word_out = final_word_out - # ************************************************************************* # other # ************************************************************************* - def graph(self, edge_labels='words_in_out'): """ - Returns the graph of the finite state machine with labeled + Return the graph of the finite state machine with labeled vertices and labeled edges. INPUT: @@ -9930,7 +9732,7 @@ def graph(self, edge_labels='words_in_out'): :class:`DiGraph` """ if edge_labels == 'words_in_out': - label_fct = lambda t:t._in_out_label_() + label_fct = lambda t: t._in_out_label_() elif hasattr(edge_labels, '__call__'): label_fct = edge_labels else: @@ -9940,7 +9742,7 @@ def graph(self, edge_labels='words_in_out'): isolated_vertices = [] for state in self.iter_states(): transitions = state.transitions - if len(transitions) == 0: + if not transitions: isolated_vertices.append(state.label()) for t in transitions: graph_data.append((t.from_state.label(), t.to_state.label(), @@ -10017,7 +9819,7 @@ def predecessors(self, state, valid_input=None): valid_list.append(input_list) valid_input = valid_list - unhandeled_direct_predecessors = {s:[] for s in self.states() } + unhandeled_direct_predecessors = {s: [] for s in self.states()} for t in self.transitions(): if valid_input is None or t.word_in in valid_input: unhandeled_direct_predecessors[t.to_state].append(t.from_state) @@ -10144,8 +9946,7 @@ def number_of_words(self, variable=var('n'), NotImplementedError: Finite State Machine must be deterministic. """ from sage.modules.free_module_element import vector - from sage.arith.all import falling_factorial - from sage.rings.integer_ring import ZZ + from sage.arith.all import binomial from sage.symbolic.ring import SR if base_ring is None: base_ring = QQbar @@ -10155,7 +9956,7 @@ def jordan_block_power(block, exponent): return matrix(block.nrows(), block.nrows(), lambda i, j: eigenvalue**(exponent-(j-i)) * - falling_factorial(exponent, j-i) / ZZ(j-i).factorial() + binomial(exponent, j - i) if j >= i else 0) if not self.is_deterministic(): @@ -10174,7 +9975,7 @@ def jordan_block_power(block, exponent): def asymptotic_moments(self, variable=var('n')): r""" - Returns the main terms of expectation and variance of the sum + Return the main terms of expectation and variance of the sum of output labels and its covariance with the sum of input labels. @@ -10605,9 +10406,11 @@ def get_matrix(fsm, x, y): y = R.symbol() z = R.symbol() M = get_matrix(self, x, y) + def substitute_one(g): return g.subs({x: 1, y: 1, z: 1}) else: + def substitute_one(g): # the result of the substitution shall live in QQ, # not in the polynomial ring R, so the method @@ -10975,8 +10778,7 @@ def default_is_zero(expression): def entry(transition): word_out = transition.word_out - if len(word_out) == 0 or ( - len(word_out) == 1 and not test(word_out[0])): + if not word_out or (len(word_out) == 1 and not test(word_out[0])): return transition.word_in[0] else: return 0 @@ -10984,7 +10786,6 @@ def entry(transition): relabeled = self.relabeled() n = len(relabeled.states()) assert [s.label() for s in relabeled.states()] == list(range(n)) - from sage.rings.integer_ring import ZZ entry_vector = vector(ZZ(s.is_initial) for s in relabeled.states()) exit_vector = vector([1] * n) @@ -11015,17 +10816,14 @@ def entry(transition): # ring, extend it instead of creating a univariate # polynomial ring over a polynomial ring. This # should improve performance. - R = PolynomialRing( - base_ring.base_ring(), - base_ring.variable_names() - + ('Z_waiting_time',)) + R = PolynomialRing(base_ring.base_ring(), + base_ring.variable_names() + + ('Z_waiting_time',)) else: R = PolynomialRing(base_ring, 'Z_waiting_time') Z = R.gens()[-1] - system_matrix = identity_matrix(n) - Z * \ - transition_matrix - G = entry_vector * system_matrix.solve_right( - exit_vector) + system_matrix = identity_matrix(n) - Z * transition_matrix + G = entry_vector * system_matrix.solve_right(exit_vector) expectation = G.subs({Z: 1}) variance = 2 * G.derivative(Z).subs({Z: 1}) \ + expectation \ @@ -11037,18 +10835,13 @@ def entry(transition): return {'expectation': expectation, 'variance': variance} - def is_monochromatic(self): """ - Checks whether the colors of all states are equal. - - INPUT: - - Nothing. + Check whether the colors of all states are equal. OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` EXAMPLES:: @@ -11063,7 +10856,6 @@ def is_monochromatic(self): """ return equal(s.color for s in self.iter_states()) - def language(self, max_length=None, **kwargs): r""" Return all words that can be written by this transducer. @@ -11158,7 +10950,7 @@ def language(self, max_length=None, **kwargs): it._finished_ = [] -#***************************************************************************** +# **************************************************************************** def is_Automaton(FSM): @@ -11278,13 +11070,13 @@ def _repr_(self): def _latex_transition_label_(self, transition, format_function=None): r""" - Returns the proper transition label. + Return the proper transition label. INPUT: - - ``transition`` - a transition + - ``transition`` -- a transition - - ``format_function`` - a function formatting the labels + - ``format_function`` -- a function formatting the labels OUTPUT: @@ -11311,10 +11103,9 @@ def _latex_transition_label_(self, transition, format_function = latex return format_function(transition.word_in) - def intersection(self, other, only_accessible_components=True): """ - Returns a new automaton which accepts an input if it is + Return a new automaton which accepts an input if it is accepted by both given automata. INPUT: @@ -11409,19 +11200,13 @@ def function(transition1, transition2): function, only_accessible_components=only_accessible_components) - cartesian_product = intersection - def determinisation(self): """ - Returns a deterministic automaton which accepts the same input + Return a deterministic automaton which accepts the same input words as the original one. - INPUT: - - Nothing. - OUTPUT: A new automaton, which is deterministic. @@ -11596,10 +11381,9 @@ def set_transition(states, letter): return result - def minimization(self, algorithm=None): """ - Returns the minimization of the input automaton as a new automaton. + Return the minimization of the input automaton as a new automaton. INPUT: @@ -11672,10 +11456,9 @@ def minimization(self, algorithm=None): else: raise NotImplementedError("Algorithm '%s' is not implemented. Choose 'Moore' or 'Brzozowski'" % algorithm) - def _minimization_Brzozowski_(self): """ - Returns a minimized automaton by using Brzozowski's algorithm. + Return a minimized automaton by using Brzozowski's algorithm. See also :meth:`.minimization`. @@ -11690,10 +11473,9 @@ def _minimization_Brzozowski_(self): """ return self.transposition().determinisation().transposition().determinisation() - def _minimization_Moore_(self): """ - Returns a minimized automaton by using Moore's algorithm. + Return a minimized automaton by using Moore's algorithm. See also :meth:`.minimization`. @@ -11712,10 +11494,9 @@ def _minimization_Moore_(self): if self.is_deterministic(): return self.quotient(self.equivalence_classes()) else: - raise NotImplementedError("Minimization via Moore's Algorithm is only " \ + raise NotImplementedError("Minimization via Moore's Algorithm is only " "implemented for deterministic finite state machines") - def complement(self): r""" Return the complement of this automaton. @@ -11802,7 +11583,7 @@ def is_equivalent(self, other): B = other.minimization().relabeled() labels = {B.process(path)[1].label(): state.label() - for (state, path) in six.iteritems(address)} + for (state, path) in address.items()} try: return A == B.relabeled(labels=labels) except KeyError: @@ -12204,7 +11985,6 @@ def shannon_parry_markov_chain(self): raise NotImplementedError("Automaton must be strongly connected.") if not all(s.is_final for s in self.iter_states()): raise NotImplementedError("All states must be final.") - from sage.rings.integer_ring import ZZ M = self.adjacency_matrix().change_ring(ZZ) states = {state: i for i, state in enumerate(self.iter_states())} w_all = sorted(M.eigenvectors_right(), @@ -12233,8 +12013,8 @@ def shannon_parry_markov_chain(self): P.state(s.label()).color = 1/(w[states[s]] * ff) P.state(s.label()).initial_probability = w[states[s]] * u[states[s]] return P - - + + def with_output(self, word_out_function=None): r""" Construct a transducer out of this automaton. @@ -12382,7 +12162,7 @@ def language(self, max_length=None, **kwargs): return T.language(max_length) -#***************************************************************************** +# **************************************************************************** def is_Transducer(FSM): @@ -12482,13 +12262,13 @@ def _repr_(self): def _latex_transition_label_(self, transition, format_function=None): r""" - Returns the proper transition label. + Return the proper transition label. INPUT: - - ``transition`` - a transition + - ``transition`` -- a transition - - ``format_function`` - a function formatting the labels + - ``format_function`` -- a function formatting the labels OUTPUT: @@ -12516,10 +12296,9 @@ def _latex_transition_label_(self, transition, return (format_function(transition.word_in) + "\\mid " + format_function(transition.word_out)) - def intersection(self, other, only_accessible_components=True): """ - Returns a new transducer which accepts an input if it is accepted by + Return a new transducer which accepts an input if it is accepted by both given finite state machines producing the same output. INPUT: @@ -12821,14 +12600,9 @@ def final_function(*states): final_function=final_function, only_accessible_components=only_accessible_components) - def simplification(self): """ - Returns a simplified transducer. - - INPUT: - - Nothing. + Return a simplified transducer. OUTPUT: @@ -13225,10 +12999,10 @@ class is created and is used during the processing. result = super(Transducer, self).process(*args, **options) if (condensed_output and not result or - not options['full_output'] and result is None): - raise ValueError("Invalid input sequence.") + not options['full_output'] and result is None): + raise ValueError("Invalid input sequence.") if condensed_output and len(result) >= 2: - raise ValueError("Found more than one accepting path.") + raise ValueError("Found more than one accepting path.") if condensed_output: return result[0] @@ -13273,7 +13047,7 @@ def _process_convert_output_(self, output_data, **kwargs): return output -#***************************************************************************** +# **************************************************************************** class _FSMTapeCache_(SageObject): @@ -13371,14 +13145,9 @@ def __init__(self, tape_cache_manager, tape, tape_ended, self.tape_cache_manager.append(self) self.cache = tuple(collections.deque() for _ in self.tape) - def _repr_(self): """ - Returns a string representation of ``self``. - - INPUT: - - Nothing. + Return a string representation of ``self``. OUTPUT: @@ -13435,7 +13204,7 @@ def __deepcopy__(self, memo): def deepcopy(self, memo=None): """ - Returns a deepcopy of ``self``. + Return a deepcopy of ``self``. INPUT: @@ -13519,10 +13288,9 @@ def read(self, track_number): return (True, newval) - def finished(self, track_number=None): r""" - Returns whether the tape (or a particular track) has reached an + Return whether the tape (or a particular track) has reached an end, i.e., there are no more letters in the cache and nothing more to read on the original tape. @@ -13533,7 +13301,7 @@ def finished(self, track_number=None): OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` TESTS:: @@ -13688,7 +13456,7 @@ def preview_word(self, track_number=None, length=1, return_word=False): def compare_to_tape(self, track_number, word): """ - Returns whether it is possible to read ``word`` from the given + Return whether it is possible to read ``word`` from the given track successfully. INPUT: @@ -13699,7 +13467,7 @@ def compare_to_tape(self, track_number, word): OUTPUT: - ``True`` or ``False``. + ``True`` or ``False`` TESTS:: @@ -13949,7 +13717,7 @@ def _transition_possible_test_(self, word_in): for track_number, word in enumerate(word_in_transposed)) -#***************************************************************************** +# **************************************************************************** class _FSMTapeCacheDetectEpsilon_(_FSMTapeCache_): @@ -14021,7 +13789,7 @@ def _transition_possible_test_(self, word_in): return self._transition_possible_epsilon_(word_in) -#***************************************************************************** +# **************************************************************************** class _FSMTapeCacheDetectAll_(_FSMTapeCache_): @@ -14080,7 +13848,7 @@ def compare_to_tape(self, track_number, word): return True -#***************************************************************************** +# **************************************************************************** def tupleofwords_to_wordoftuples(tupleofwords): @@ -14133,13 +13901,14 @@ def wordoftuples_to_tupleofwords(wordoftuples): """ if not equal(len(t) for t in wordoftuples): raise ValueError("Not all entries of input have the same length.") + def remove_empty_letters(word): return [letter for letter in word if letter is not None] return tuple(remove_empty_letters(word) for word in zip(*wordoftuples)) -#***************************************************************************** +# **************************************************************************** def is_FSMProcessIterator(PI): @@ -14155,7 +13924,7 @@ def is_FSMProcessIterator(PI): return isinstance(PI, FSMProcessIterator) -#***************************************************************************** +# **************************************************************************** class FSMProcessIterator(SageObject, @@ -14411,11 +14180,7 @@ class Current(dict): """ def __repr__(self): """ - Returns a nice representation of ``self``. - - INPUT: - - Nothing. + Return a nice representation of ``self``. OUTPUT: @@ -14439,8 +14204,8 @@ def __repr__(self): """ data = sorted( (state, pos, tape_cache, outputs) - for pos, states in six.iteritems(self) - for state, (tape_cache, outputs) in six.iteritems(states)) + for pos, states in self.items() + for state, (tape_cache, outputs) in states.items()) branch = "branch" if len(data) == 1 else "branches" result = "process (%s %s)" % (len(data), branch) for s, sdata in itertools.groupby(data, lambda x: x[0]): @@ -14716,7 +14481,7 @@ def _push_branches_(self, state, tape_cache, outputs): 'but output is written.' % (state,)) for eps_state, eps_outputs in \ - six.iteritems(state._epsilon_successors_(self.fsm)): + state._epsilon_successors_(self.fsm).items(): if eps_state == state: continue # "eps_state == state" means epsilon cycle @@ -14909,18 +14674,16 @@ def step(current_state, input_tape, outputs): return states_dict = self._current_.pop(heapq.heappop(self._current_positions_)) - for state, branch in six.iteritems(states_dict): + for state, branch in states_dict.items(): step(state, branch.tape_cache, branch.outputs) return self._current_ - next = __next__ - def result(self, format_output=None): """ - Returns the already finished branches during process. + Return the already finished branches during process. INPUT: @@ -14967,7 +14730,7 @@ def result(self, format_output=None): def preview_word(self, track_number=None, length=1, return_word=False): """ - Reads a word from the input tape. + Read a word from the input tape. INPUT: @@ -15022,7 +14785,7 @@ def preview_word(self, track_number=None, length=1, return_word=False): track_number, length, return_word) -#***************************************************************************** +# **************************************************************************** class _FSMProcessIteratorEpsilon_(FSMProcessIterator): @@ -15469,7 +15232,7 @@ def __init__(self, *args, **kwargs): return super(_FSMProcessIteratorAll_, self).__init__(*args, **kwargs) -#***************************************************************************** +# **************************************************************************** @cached_function @@ -15479,14 +15242,6 @@ def setup_latex_preamble(): to the preamble of Latex so that the finite state machines can be drawn nicely. - INPUT: - - Nothing. - - OUTPUT: - - Nothing. - See the section on :ref:`finite_state_machine_LaTeX_output` in the introductory examples of this module. From e96c6ee56ad04152bf3c657e1f720ac2716f8e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 09:08:00 +0200 Subject: [PATCH 157/476] trac 29641 fix some details --- src/sage/combinat/finite_state_machine.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 61ebd590769..304ccaed330 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -1091,7 +1091,7 @@ def startswith(list_, prefix): """ if len(prefix) > len(list_): return False - return all(x == y for x, y in zip(list_, prefix)) + return list_[:len(prefix)] == prefix # **************************************************************************** @@ -2450,8 +2450,7 @@ def __eq__(self, other): True """ if not is_FSMTransition(other): - raise TypeError('Only instances of FSMTransition ' - 'can be compared.') + return False return self.from_state == other.from_state \ and self.to_state == other.to_state \ and self.word_in == other.word_in \ From b2e93e1e8133e14a7d6edbd53655a788ce596998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 09:20:34 +0200 Subject: [PATCH 158/476] trac 29641 another fix --- src/sage/combinat/finite_state_machine.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 304ccaed330..0155251214b 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -3990,8 +3990,7 @@ def __eq__(self, other): True """ if not is_FiniteStateMachine(other): - raise TypeError('Only instances of FiniteStateMachine ' - 'can be compared.') + return False if len(self._states_) != len(other._states_): return False colors_equal = True From bff915efa374aac254aad0eacd5250eca1836f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 10:54:06 +0200 Subject: [PATCH 159/476] spring cleanup for typos (may 2020) --- src/sage/algebras/commutative_dga.py | 2 +- .../algebras/lie_algebras/classical_lie_algebra.py | 8 ++++---- src/sage/algebras/lie_algebras/verma_module.py | 8 ++++---- src/sage/categories/bialgebras_with_basis.py | 2 +- src/sage/categories/pushout.py | 6 +++--- src/sage/combinat/integer_vectors_mod_permgroup.py | 9 +++++---- .../dynamics/arithmetic_dynamics/projective_ds.py | 4 ++-- src/sage/ext_data/threejs/threejs_template.html | 4 ++-- src/sage/functions/prime_pi.pyx | 8 ++++---- src/sage/geometry/polyhedron/base.py | 7 +++---- .../polyhedron/combinatorial_polyhedron/base.pyx | 8 ++++---- .../combinatorial_polyhedron/list_of_faces.pyx | 2 +- .../graphs/graph_decompositions/clique_separators.pyx | 3 ++- src/sage/libs/flint/flint_ntl_wrap.h | 2 +- src/sage/libs/flint/flint_wrap.h | 2 +- .../differentiable/degenerate_submanifold.py | 2 +- src/sage/matrix/action.pyx | 9 +++++---- src/sage/matroids/extension.pyx | 11 ++++++----- src/sage/modular/cusps_nf.py | 2 +- src/sage/modular/modform_hecketriangle/readme.py | 2 +- src/sage/rings/integer.pyx | 2 +- src/sage/rings/localization.py | 5 +---- src/sage/rings/number_field/S_unit_solver.py | 2 +- src/sage/rings/polynomial/skew_polynomial_ring.py | 4 ++-- src/sage/rings/puiseux_series_ring_element.pyx | 6 +++--- src/sage/rings/qqbar.py | 2 +- src/sage/rings/valuation/inductive_valuation.py | 8 ++++---- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/elliptic_curves/mod_sym_num.pyx | 8 ++++---- src/sage/schemes/generic/algebraic_scheme.py | 4 ++-- .../hyperelliptic_finite_field.py | 10 +++++----- src/sage/structure/parent.pyx | 6 +++--- 32 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 24d0c041a8d..e6722c5c671 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -2533,7 +2533,7 @@ def minimal_model(self, i=3, max_iterations=3): def extend(phi, ndegrees, ndifs, nimags, nnames): """ - Extend phi to a new algebra with new genererators, labeled by nnames + Extend phi to a new algebra with new generators, labeled by nnames """ B = phi.domain() names = [str(g) for g in B.gens()] diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index 30e5176fdde..9bceec86923 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -14,15 +14,15 @@ - Travis Scrimshaw (2019-07-09): Implemented compact real form """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from collections import OrderedDict from sage.misc.abstract_method import abstract_method @@ -238,7 +238,7 @@ def epsilon(self, i, h): """ return h[i-1,i-1] - # Do we want this to be optional or requried? + # Do we want this to be optional or required? # There probably is a generic implementation we can do. @abstract_method(optional=True) def simple_root(self, i, h): diff --git a/src/sage/algebras/lie_algebras/verma_module.py b/src/sage/algebras/lie_algebras/verma_module.py index 8781879bc8c..c59d964499f 100644 --- a/src/sage/algebras/lie_algebras/verma_module.py +++ b/src/sage/algebras/lie_algebras/verma_module.py @@ -11,15 +11,15 @@ and return as the ``construction()``. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method @@ -651,7 +651,7 @@ def _acted_upon_(self, scalar, self_on_left=False): try: scalar = P._pbw(scalar) except (ValueError, TypeError): - # Cannot be made into a PBW element, so propogate it up + # Cannot be made into a PBW element, so propagate it up return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index f7ced53db0a..831bab3f068 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -82,7 +82,7 @@ def convolution_product(self, *maps): EXAMPLES: We construct some maps: the identity, the antipode and - projection onto the homogeneous componente of degree 2:: + projection onto the homogeneous component of degree 2:: sage: Id = lambda x: x sage: Antipode = lambda x: x.antipode() diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 27e436c6360..6f9d44fea82 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1260,7 +1260,7 @@ def __init__(self, gens, order, implementation): def _apply_functor_to_morphism(self, f): """ - Morphisms for inifinite polynomial rings are not implemented yet. + Morphisms for infinite polynomial rings are not implemented yet. TESTS:: @@ -1270,10 +1270,10 @@ def _apply_functor_to_morphism(self, f): sage: R.construction()[0](f) # indirect doctest Traceback (most recent call last): ... - NotImplementedError: Morphisms for inifinite polynomial rings are not implemented yet. + NotImplementedError: Morphisms for infinite polynomial rings are not implemented yet. """ - raise NotImplementedError("Morphisms for inifinite polynomial rings are not implemented yet.") + raise NotImplementedError("Morphisms for infinite polynomial rings are not implemented yet.") def _apply_functor(self, R): """ diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index 98f3c656469..684c7508564 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -1,14 +1,14 @@ r""" Integer vectors modulo the action of a permutation group """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010-12 Nicolas Borie # # Distributed under the terms of the GNU General Public License (GPL) # # The full text of the GPL is available at: -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from sage.structure.unique_representation import UniqueRepresentation @@ -24,6 +24,7 @@ from sage.combinat.integer_vector import IntegerVectors + class IntegerVectorsModPermutationGroup(UniqueRepresentation): r""" Returns an enumerated set containing integer vectors which are @@ -963,5 +964,5 @@ def check(self): if self.parent()._sum is not None: assert sum(self) == self.parent()._sum, '%s should be a integer vector of sum %s'%(self, self.parent()._sum) if self.parent()._max_part >= 0: - assert max(self) <= self.parent()._max_part, 'Entries of %s must be inferiors to %s'%(self, self.parent()._max_part) + assert max(self) <= self.parent()._max_part, 'Entries of %s must be inferior to %s'%(self, self.parent()._max_part) assert self.parent().is_canonical(self) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 41cbe752f7a..52c436c51f2 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4794,7 +4794,7 @@ def reduced_form(self, **kwds): ) """ if self.domain().ambient_space().dimension_relative() != 1: - return NotImplementedError('only implmeneted for dimension 1') + return NotImplementedError('only implemented for dimension 1') return_conjugation = kwds.get('return_conjugation', True) emb = kwds.get('emb', None) prec = kwds.get('prec', 300) @@ -4803,7 +4803,7 @@ def reduced_form(self, **kwds): dynatomic = algorithm = kwds.get('dynatomic', True) smallest_coeffs = kwds.get('smallest_coeffs', True) if smallest_coeffs: - if self.base_ring() not in [ZZ,QQ]: + if self.base_ring() not in [ZZ, QQ]: raise NotImplementedError("smallest coeff only over ZZ or QQ") check_min = kwds.get('check_minimal', True) from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import smallest_dynamical diff --git a/src/sage/ext_data/threejs/threejs_template.html b/src/sage/ext_data/threejs/threejs_template.html index 2833d5021fe..ff1ebb9b829 100644 --- a/src/sage/ext_data/threejs/threejs_template.html +++ b/src/sage/ext_data/threejs/threejs_template.html @@ -133,7 +133,7 @@ var sprite = new THREE.Sprite( new THREE.SpriteMaterial( { map: texture } ) ); sprite.position.set( x, y, z ); - // Set the initial scale based on plot size to accomodate orthographic projection. + // Set the initial scale based on plot size to accommodate orthographic projection. // For other projections, the scale will get reset each frame based on camera distance. var scale = midToCorner/2; sprite.scale.set( scale, scale*.25 ); // ratio of canvas width to height @@ -360,7 +360,7 @@ renderer.render( scene, camera ); // Resize text based on distance from camera. - // Not neccessary for orthographic due to the nature of the projection (preserves sizes). + // Not necessary for orthographic due to the nature of the projection (preserves sizes). if ( !camera.isOrthographicCamera ) { for ( var i=0 ; i < scene.children.length ; i++ ) { if ( scene.children[i].type === 'Sprite' ) { diff --git a/src/sage/functions/prime_pi.pyx b/src/sage/functions/prime_pi.pyx index a29dce47bff..60ddf604af1 100644 --- a/src/sage/functions/prime_pi.pyx +++ b/src/sage/functions/prime_pi.pyx @@ -18,15 +18,15 @@ EXAMPLES:: True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009,2011 R. Andrew Ohana # Copyright (C) 2009 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cypari2.paridecl cimport * from cysignals.signals cimport * @@ -274,7 +274,7 @@ cdef class PrimePi(BuiltinFunction): cdef uint32_t _cached_count(self, uint32_t p): r""" For p < 65536, returns the value stored in ``self.__smallPi[p]``. For - p <= ``self.__maxSieve``, uses a binary seach on ``self.__primes`` to + p <= ``self.__maxSieve``, uses a binary search on ``self.__primes`` to compute pi(p). """ # inspired by Yann Laigle-Chapuy's suggestion diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 01989bbd80e..7e8f04713ab 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -2,7 +2,7 @@ Base class for polyhedra """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Marshall Hampton # Copyright (C) 2011 Volker Braun # Copyright (C) 2015 Jean-Philippe Labbe @@ -13,7 +13,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from __future__ import division, print_function, absolute_import @@ -3253,14 +3253,13 @@ def is_simple(self): sage: p = Polyhedron([[0,0,0],[4,4,0],[4,0,0],[0,4,0],[2,2,2]]) sage: p.is_simple() False - """ if not self.is_compact(): return False return self.combinatorial_polyhedron().is_simple() def simpliciality(self): r""" - Return the largest interger `k` such that the polytope is `k`-simplicial. + Return the largest integer `k` such that the polytope is `k`-simplicial. A polytope is `k`-simplicial, if every `k`-face is a simplex. If `self` is a simplex, returns its dimension. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index d7d27efc5f0..83c922e05d2 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1471,13 +1471,13 @@ cdef class CombinatorialPolyhedron(SageObject): else: facet_names = self.facet_names() if facet_names is None: - # No names where provided at initializiation. - facet_names = [("H",i) for i in range(n_facets)] + # No names where provided at initialisation. + facet_names = [("H", i) for i in range(n_facets)] Vrep = self.Vrep() if Vrep is None: - # No names where provided at initializiation. - Vrep = [("V",i) for i in range(n_Vrep)] + # No names where provided at initialisation. + Vrep = [("V", i) for i in range(n_Vrep)] vertices = Vrep + facet_names edges = tuple((Vrep[j], facet_names[n_facets - 1 - i]) for i,facet in enumerate(facet_iter) for j in facet.ambient_V_indices()) 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..2db092697a2 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -347,7 +347,7 @@ cdef class ListOfFaces: return count_atoms(faces[0], face_length) # ``maybe_newfaces`` are all intersection of ``faces[n_faces -1]`` with previous faces. - # It needs to be allcoated to store those faces. + # It needs to be allocated to store those faces. cdef ListOfFaces maybe_newfaces_mem = ListOfFaces(n_faces, face_length*64) cdef uint64_t **maybe_newfaces = maybe_newfaces_mem.data diff --git a/src/sage/graphs/graph_decompositions/clique_separators.pyx b/src/sage/graphs/graph_decompositions/clique_separators.pyx index 3df6224d839..3c4e1b06723 100644 --- a/src/sage/graphs/graph_decompositions/clique_separators.pyx +++ b/src/sage/graphs/graph_decompositions/clique_separators.pyx @@ -157,6 +157,7 @@ cdef inline bint is_clique(short_digraph sd, vector[int] Hx): return False return True + def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=False): r""" Return the atoms of the decomposition of `G` by clique minimal separators. @@ -200,7 +201,7 @@ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=Fal OUTPUT: - By default, return a tuple `(A, S_c)`, where `A` is the list of atoms of - the graph in the order of dicovery, and `S_c` is the list of clique + the graph in the order of discovery, and `S_c` is the list of clique separators, with possible repetitions, in the order the separator has been considered. If furthermore ``separators`` is ``True``, return a tuple `(A, S_h, S_c)`, where `S_c` is the list of considered separators of the graph diff --git a/src/sage/libs/flint/flint_ntl_wrap.h b/src/sage/libs/flint/flint_ntl_wrap.h index 058d13b2e92..841d990817d 100644 --- a/src/sage/libs/flint/flint_ntl_wrap.h +++ b/src/sage/libs/flint/flint_ntl_wrap.h @@ -15,7 +15,7 @@ #include /* If flint was already previously included via another header (e.g. - * arb_wrap.h) then it may be neessary to redefine ulong and slong again */ + * arb_wrap.h) then it may be necessary to redefine ulong and slong again */ #ifndef ulong #define ulong mp_limb_t diff --git a/src/sage/libs/flint/flint_wrap.h b/src/sage/libs/flint/flint_wrap.h index 179597d2d56..b68c93ce810 100644 --- a/src/sage/libs/flint/flint_wrap.h +++ b/src/sage/libs/flint/flint_wrap.h @@ -24,7 +24,7 @@ #include /* If flint was already previously included via another header (e.g. - * arb_wrap.h) then it may be neessary to redefine ulong and slong again */ + * arb_wrap.h) then it may be necessary to redefine ulong and slong again */ #ifndef ulong #define ulong mp_limb_t diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index 43e097f2e3c..2aada97535b 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -425,7 +425,7 @@ def list_of_screens(self): def set_transverse(self, rigging=None, normal=None): r""" - For setting a transversal disttribution of the degenerate submanifold. + For setting a transversal distribution of the degenerate submanifold. according to the type of the submanifold amoung the 4 possible types, one must enter a list of normal transversal vector fields and/or a list of transversal and not normal vector fields spanning a transverse diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 12000c49764..14d2d5cc414 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -50,15 +50,15 @@ AUTHOR: - Robert Bradshaw (2007-09): Initial version. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Robert Bradshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import operator @@ -517,9 +517,10 @@ cdef class PolymapMatrixAction(MatrixMulAction): """ return f._polymap_times_matrix_(mat, self._codomain) + cdef class MatrixSchemePointAction(MatrixMulAction): r""" - Action class for left multiplication of schemes points by matricies. + Action class for left multiplication of schemes points by matrices. """ def __init__(self, G, S): """ diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index c0156678def..cb47076bebb 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -18,7 +18,7 @@ AUTHORS: Methods ======= """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Rudi Pendavingh # Copyright (C) 2013 Stefan van Zwam # @@ -26,13 +26,14 @@ Methods # 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/ +# **************************************************************************** include 'sage/data_structures/bitset.pxi' from .basis_matroid cimport BasisMatroid from sage.arith.all import binomial + cdef class CutNode: """ An internal class used for creating linear subclasses of a matroids in a @@ -41,11 +42,11 @@ cdef class CutNode: A linear subclass is a set of hyperplanes `mc` with the property that certain sets of hyperplanes must either be fully contained in `mc` or intersect `mc` in at most 1 element. The way we generate them is by a - depth-first seach. This class represents a node in the search tree. + depth-first search. This class represents a node in the search tree. It contains the set of hyperplanes selected so far, as well as a collection of hyperplanes whose insertion has been explored elsewhere in - the seach tree. + the search tree. The class has methods for selecting a hyperplane to insert, for inserting hyperplanes and closing the set to become a linear subclass again, and for diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index da0cb670cc0..c4c414a0d2a 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -1100,7 +1100,7 @@ def number_of_Gamma0_NFCusps(N): OUTPUT: - ingeter -- the number of orbits of cusps under Gamma0(N)-action. + integer -- the number of orbits of cusps under Gamma0(N)-action. EXAMPLES:: diff --git a/src/sage/modular/modform_hecketriangle/readme.py b/src/sage/modular/modform_hecketriangle/readme.py index cc89da2da80..c5455b39a88 100644 --- a/src/sage/modular/modform_hecketriangle/readme.py +++ b/src/sage/modular/modform_hecketriangle/readme.py @@ -602,7 +602,7 @@ - Specifying the form as a rational function in the basic generators (see below) - For weakly holomorphic modular forms it is possible to exactly determine the form by specifying (sufficiently many) initial coefficients of its Fourier expansion. - - There is even hope (no garantuee) to determine a (exact) form from + - There is even hope (no guarantee) to determine a (exact) form from the initial numerical coefficients (see below). - By specifying the coefficients with respect to a basis of the space (if the corresponding space supports coordinate vectors) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 1879407eb16..44936e6a6a4 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -7254,7 +7254,7 @@ cdef class int_to_Z(Morphism): sage: type(1 + 2r) - This is intented for internal use by the coercion system, + This is intended for internal use by the coercion system, to facilitate fast expressions mixing ints and more complex Python types. Note that (as with all morphisms) the input is forcably coerced to the domain ``int`` if it is not diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index 652d4898bb7..91cec331999 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -239,8 +239,6 @@ def normalize_additional_units(base_ring, add_units, warning=True): return sorted(set(add_units_result)) - - class LocalizationElement(IntegralDomainElement): """ Element class for localizations of integral domains @@ -476,13 +474,12 @@ class Localization(IntegralDomain, UniqueRepresentation): the exact division operator `//` (:meth:`sage.structure.element.Element.__floordiv__`) in order to guarantee an successful application. - INPUT: - ``base_ring`` -- an instance of :class:`Ring` allowing the construction of :meth:`fraction_field` (that is an integral domain) - ``additional_units`` -- tuple of elements of ``base_ring`` which should be turned into units - ``names`` -- passed to :class:`IntegralDomain` - - ``normalize`` -- (optinal, default: True) passed to :class:`IntegralDomain` + - ``normalize`` -- (optional, default: True) passed to :class:`IntegralDomain` - ``category`` -- (optional, default: None) passed to :class:`IntegralDomain` - ``warning`` -- (optional, default: True) to supress a warning which is thrown if self cannot be represented uniquely diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index 7612ed0ddc0..0365c4313f1 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -1931,7 +1931,7 @@ def ev_flatten(vec): rfv_to_ev = {} - # We build a second dictionary of dictiories. + # We build a second dictionary of dictionaries. # comp_exp_vec[q] is the dictionary mod q which assigns to each exponent vector # a list of 'complementary' exponent vectors. diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 1c30938bc73..2b65396ce2d 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -5,7 +5,7 @@ which constructs a general dense skew univariate polynomials over commutative base rings with automorphisms over the base rings. This is the set of formal polynomials where the coefficients are written on the left of the variable of the skew polynomial ring. The modified multiplication -operation over elements of the base ring is extended to all elements of the skew poynomial ring +operation over elements of the base ring is extended to all elements of the skew polynomial ring by associativity and distributivity. This module also provides :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order` @@ -1396,7 +1396,7 @@ def center(self, name=None, names=None, default=False): sage: P.parent() is S True - together with a converion map in the reverse direction:: + together with a conversion map in the reverse direction:: sage: Zy(x^6 + 2*x^3 + 3) y^2 + 2*y + 3 diff --git a/src/sage/rings/puiseux_series_ring_element.pyx b/src/sage/rings/puiseux_series_ring_element.pyx index 29be2de67af..d4bedc3428f 100644 --- a/src/sage/rings/puiseux_series_ring_element.pyx +++ b/src/sage/rings/puiseux_series_ring_element.pyx @@ -99,7 +99,7 @@ REFERENCES: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from sage.arith.functions import lcm @@ -141,7 +141,7 @@ cdef class PuiseuxSeries(AlgebraElement): - ``f`` -- one of the following types of inputs: * instance of :class:`PuiseuxSeries` - * instance that can be coerced into the Laurent sersies ring of the parent + * instance that can be coerced into the Laurent series ring of the parent - ``e`` -- integer (default: 1) the ramification index @@ -182,7 +182,7 @@ cdef class PuiseuxSeries(AlgebraElement): # -------------------------------------------------------- # choose a representative for this Puiseux series having - # minimal ramification index. This is neccessary because + # minimal ramification index. This is necessary because # some methods need it as minimal as possible (for example # :meth:`laurent_series' or :meth:`power_series`) # -------------------------------------------------------- diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index dc6556c8902..fb169169da8 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -877,7 +877,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): # # As nbruin pointed out during the review of Trac #25390, # this can be accomplished more efficiently using the resultant - # of the polynomial with the number field's minimial polynomial. + # of the polynomial with the number field's minimal polynomial. # # We use two auxiliary polynomial rings: # diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index de73549d9d2..a3bf9ad3275 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -29,14 +29,14 @@ An introduction is also given in Chapter 4 of [Rüt2014]_. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016-2018 Julian Rüth # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from .valuation import DiscreteValuation, InfiniteDiscretePseudoValuation @@ -676,7 +676,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a INPUT: - - ``G`` -- a sqaurefree monic non-constant integral polynomial ``G`` + - ``G`` -- a squarefree monic non-constant integral polynomial ``G`` which is not an :meth:`equivalence unit ` - ``principal_part_bound`` -- an integer or ``None`` (default: diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 592bb68dc65..360fb88dc6a 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -2291,7 +2291,7 @@ def _coordinate_functions(self): sage: C._coordinate_functions (1, y, z) """ - # homogeneous cooridinate functions + # homogeneous coordinate functions coords = list(self._open_affine._coordinate_functions) coords.insert(self._open_affine_index, self._function_field.one()) return tuple(coords) diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index 6b661bd14aa..6a4e94c6285 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -147,7 +147,7 @@ AUTHOR: """ -#**************************************************************************** +# *************************************************************************** # Copyright (C) 2016 Chris Wuthrich # # Distributed under the terms of the GNU General Public License (GPL) @@ -159,8 +159,8 @@ AUTHOR: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from __future__ import print_function from cysignals.memory cimport sig_malloc, sig_free, sig_realloc @@ -1110,7 +1110,7 @@ cdef class ModularSymbolNumerical: # now to the bound for the unitary cusps # this is a bit better because they - # are definied over Q + # are defined over Q t0 = E0.torsion_order() if cinf == 1: t0 *= Integer(2) diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 46d84da174b..b3af58476dc 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -1716,9 +1716,9 @@ def rational_points(self, **kwds): In the case of numerically approximated points, the points are returned over as points of the ambient space. - For a dimesion greater than 0 scheme, depending on bound size, either the + For a dimension greater than 0 scheme, depending on bound size, either the points in the ambient space are enumerated or a sieving algorithm lifting points - modulo primes is used. See the documention in homset for the details of the + modulo primes is used. See the documentation in homset for the details of the sieving algorithm. INPUT: diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 372d33a6007..62a7dc2b30a 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -26,7 +26,7 @@ - Dean Bisogno (2017): Fixed Hasse-Witt computation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Kohel # Copyright (C) 2007 Robert Bradshaw # Copyright (C) 2010 Alyson Deines , Marina Gresham @@ -45,10 +45,9 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import -from six.moves import range from sage.rings.all import ZZ, RR, QQ, GF from sage.arith.all import binomial @@ -62,6 +61,7 @@ from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_finite_field + class HyperellipticCurve_finite_field(hyperelliptic_generic.HyperellipticCurve_generic, ProjectivePlaneCurve_finite_field): def _frobenius_coefficient_bound_charpoly(self): @@ -1299,7 +1299,7 @@ def cardinality_exhaustive(self, extension_degree=1, algorithm=None): def cardinality_hypellfrob(self, extension_degree=1, algorithm=None): r""" Count points on a single extension of the base field - using the ``hypellfrob`` prgoram. + using the ``hypellfrob`` program. EXAMPLES:: diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index eb0255bf171..55a5cec3635 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -144,8 +144,8 @@ cdef bint is_Integer(x): def is_Parent(x): """ - Return True if x is a parent object, i.e., derives from - sage.structure.parent.Parent and False otherwise. + Return ``True`` if x is a parent object, i.e., derives from + sage.structure.parent.Parent and ``False`` otherwise. EXAMPLES:: @@ -1346,7 +1346,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): codomain = im_gens.universe() if isinstance(im_gens, Sequence_generic): im_gens = list(im_gens) - # Not all homsets accept catgory/check/base_map as arguments + # Not all homsets accept category/check/base_map as arguments kwds = {} if check is not None: kwds['check'] = check From 1c9e8f4196b96c443d3b3321c37b313b23cb5c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 17:52:26 +0200 Subject: [PATCH 160/476] trac 29643 one little detail in categories/pushout --- src/sage/categories/pushout.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 6f9d44fea82..c69e8562dd4 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2,7 +2,6 @@ Coercion via construction functors """ from __future__ import print_function, absolute_import -from six.moves import range import six from sage.misc.lazy_import import lazy_import @@ -646,7 +645,6 @@ def __eq__(self, other): """ c = (type(self) == type(other)) if not c: - from sage.categories.functor import IdentityFunctor_generic if isinstance(other, IdentityFunctor_generic): return True return c From 334fa3a97a1b30a5e56be3a6a8006872c03deec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 20:15:26 +0200 Subject: [PATCH 161/476] trac 29643 one more detail --- .../geometry/polyhedron/combinatorial_polyhedron/base.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 83c922e05d2..dcb3c703339 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1471,12 +1471,12 @@ cdef class CombinatorialPolyhedron(SageObject): else: facet_names = self.facet_names() if facet_names is None: - # No names where provided at initialisation. + # No names were provided at initialisation. facet_names = [("H", i) for i in range(n_facets)] Vrep = self.Vrep() if Vrep is None: - # No names where provided at initialisation. + # No names were provided at initialisation. Vrep = [("V", i) for i in range(n_Vrep)] vertices = Vrep + facet_names From 94203aa5be84a997a1fd0b37f4d58f6e8197e608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 4 May 2020 20:18:11 +0200 Subject: [PATCH 162/476] trac 29643 some more details --- src/sage/rings/valuation/inductive_valuation.py | 3 ++- .../schemes/hyperelliptic_curves/hyperelliptic_finite_field.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index a3bf9ad3275..de63cb9532b 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -1596,7 +1596,8 @@ def _test_is_equivalence_irreducible(self, **options): tester = self._tester(**options) S = tester.some_elements(self.domain().some_elements()) for f in S: - if f.is_constant(): continue + if f.is_constant(): + continue is_equivalence_irreducible = self.is_equivalence_irreducible(f) F = self.equivalence_decomposition(f) tester.assertEqual(is_equivalence_irreducible, len(F)==0 or (len(F)==1 and F[0][1]==1)) diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 62a7dc2b30a..f4dde5bf06e 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -839,7 +839,8 @@ def points(self): from sage.rings.finite_rings.finite_field_constructor import zech_log_bound try: return self.__points - except AttributeError: pass + except AttributeError: + pass if self.base_ring().is_prime_field(): self.__points = self._points_cache_sqrt() From bfc9c572cc65a3de4b0cc3e9d9ade6f022b808f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 7 May 2020 10:14:45 +0200 Subject: [PATCH 163/476] 29523: changes by reviewer --- src/sage/plot/plot.py | 44 +++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 6697b5c9cd6..955b7a44c03 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2250,8 +2250,9 @@ def golden_rainbow(i,lightness=0.4): plot_points = int(options.pop('plot_points')) exclude = options.pop('exclude') - initial_points = None - if exclude is not None: + if exclude is None: + initial_points = None + else: from sage.symbolic.expression import Expression if isinstance(exclude, Expression) and exclude.is_relational(): if len(exclude.variables()) > 1: @@ -2285,32 +2286,35 @@ def golden_rainbow(i,lightness=0.4): not parametric and options['scale'] in ['loglog', 'semilogx']) if is_log_scale: - f_orig = f - xrange_orig = xrange - f = lambda x: f_orig(exp(x)) - xrange = (log(xrange_orig[0]), log(xrange_orig[1])) - if not initial_points is None: - initial_points = [log(x) for x in initial_points] - - data = generate_plot_points(f, xrange, plot_points, - adaptive_tolerance, adaptive_recursion, - randomize, initial_points) + f_exp = lambda x: f(exp(x)) + log_xrange = (log(xrange[0]), log(xrange[1])) + if initial_points is None: + log_initial_points = None + else: + log_initial_points = [log(x) for x in initial_points] + data = generate_plot_points(f_exp, log_xrange, plot_points, + adaptive_tolerance, adaptive_recursion, + randomize, log_initial_points) + average_distance_between_points = abs(log_xrange[1] - log_xrange[0])/plot_points + else: + data = generate_plot_points(f, xrange, plot_points, + adaptive_tolerance, adaptive_recursion, + randomize, initial_points) + average_distance_between_points = abs(xrange[1] - xrange[0])/plot_points for i in range(len(data)-1): # If the difference between consecutive x-values is more than - # 2 times the difference between two consecutive plot points, then + # 2 times the average difference between two consecutive plot points, then # add an exclusion point. - if abs(data[i+1][0] - data[i][0]) > 2*abs(xrange[1] - xrange[0])/plot_points: + if abs(data[i+1][0] - data[i][0]) > 2*average_distance_between_points: excluded_points.append((data[i][0] + data[i+1][0])/2) # If we did a change in variables, undo it now if is_log_scale: - f = f_orig - xrange = xrange_orig - for i in range(len(data)): - data[i] = (exp(data[i][0]), data[i][1]) - for i in range(len(excluded_points)): - excluded_points[i] = exp(excluded_points[i]) + for i,(a,fa) in enumerate(data): + data[i] = (exp(a), fa) + for i,p in enumerate(excluded_points): + excluded_points[i] = exp(p) if parametric: # We need the original x-values to be able to exclude points in parametric plots From 7dbededec0ca47fd4cda07e8134aeb67e5bb6818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 7 May 2020 14:09:54 +0200 Subject: [PATCH 164/476] 29523: same if structure as before --- src/sage/plot/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 955b7a44c03..5296f60f65b 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2250,9 +2250,7 @@ def golden_rainbow(i,lightness=0.4): plot_points = int(options.pop('plot_points')) exclude = options.pop('exclude') - if exclude is None: - initial_points = None - else: + if exclude is not None: from sage.symbolic.expression import Expression if isinstance(exclude, Expression) and exclude.is_relational(): if len(exclude.variables()) > 1: @@ -2279,6 +2277,8 @@ def golden_rainbow(i,lightness=0.4): initial_points = reduce(lambda a,b: a+b, [[x - epsilon, x + epsilon] for x in excluded_points], []) + else: + initial_points = None # If we are a log scale plot on the x axis, do a change of variables # so we sample the range in log scale From 38c4efcaff17e49d5071bec8a5d41a911bf1fac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 18 Feb 2020 21:58:27 +0100 Subject: [PATCH 165/476] trying to extract pari,sage,maxima code from OEIS program field --- src/sage/databases/oeis.py | 173 +++++++++++++++++++++++++++++++------ 1 file changed, 148 insertions(+), 25 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index d774de7c0be..77cdce92fa9 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -168,9 +168,12 @@ from sage.misc.misc import verbose from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten +from sage.misc.temporary_file import tmp_filename from sage.misc.unknown import Unknown from sage.misc.misc import embedded from sage.misc.html import HtmlFragment +from sage.repl.preparse import preparse + from collections import defaultdict import re @@ -595,7 +598,7 @@ def _imaginary_entry(self, ident='A999999', keywords=''): '%o ' + ident + ' def ' + ident + '(n):\n' '%o ' + ident + ' assert(isinstance(n, (int, Integer))), "n must be an integer."\n' '%o ' + ident + ' if n < 38:\n' - '%o ' + ident + ' raise ValueError("The value %s is not accepted." %str(n)))\n' + '%o ' + ident + ' raise ValueError("The value %s is not accepted." %str(n))\n' '%o ' + ident + ' elif n == 42:\n' '%o ' + ident + ' return 2\n' '%o ' + ident + ' else:\n' @@ -632,6 +635,7 @@ def _imaginary_sequence(self, ident='A999999', keywords='sign,easy'): """ return self.find_by_entry(entry=self._imaginary_entry(ident=ident, keywords=keywords)) + class OEISSequence(SageObject, UniqueRepresentation): r""" The class of OEIS sequences. @@ -1076,7 +1080,7 @@ def natural_object(self): sage: s.natural_object().universe() Integer Ring """ - if 'cofr' in self.keywords() and not 'frac' in self.keywords(): + if 'cofr' in self.keywords() and 'frac' not in self.keywords(): from sage.rings.continued_fraction import continued_fraction return continued_fraction(self.first_terms()) elif 'cons' in self.keywords(): @@ -1832,55 +1836,174 @@ def show(self): print(re.sub('_', ' ', s).upper()) print(str(result) + '\n') - def programs(self, language='other'): + def programs(self, language='all', preparsing=True, keep_comments=False): r""" - Return programs implementing the sequence ``self`` in the given ``language``. + Return programs for the sequence ``self`` in the given ``language``. INPUT: - - ``language`` - string (default: 'other') - the language of the - program. Current values are: 'maple', 'mathematica' and 'other'. + - ``language`` -- string (default: 'all'), the chosen language. + Possible values are 'all' for the full list, or + any language name, for example 'sage', 'maple', 'mathematica', etc. + + Some further optional input is specific to sage code treatment: + + - ``preparsing`` -- boolean (default: ``True``) whether to preparse + sage code + - ``keep_comments`` -- boolean (default: ``False``) whether to keep + comments in sage code OUTPUT: - - tuple of strings (with fancy formatting). + If ``language`` is ``'all'``, this returns a sorted list of pairs + (language, code), where every language can appear several times. - .. TODO:: ask OEIS to add a "Sage program" field in the database ;) + Otherwise, this returns a list of programs in the ``language``, + each program being a tuple of strings (with fancy formatting). EXAMPLES:: sage: ee = oeis('A001113') ; ee # optional -- internet A001113: Decimal expansion of e. - sage: ee.programs()[0] # optional -- internet - '(PARI) default(realprecision, 50080); x=exp(1); for (n=1, 50000, d=floor(x); x=(x-d)*10; write("b001113.txt", n, " ", d)); \\\\ _Harry J. Smith_, Apr 15 2009' + sage: ee.programs('pari')[0] # optional -- internet + 0: default(realprecision, 50080); x=exp(1); for (n=1, 50000, d=floor(x); x=(x-d)*10; write("b001113.txt", n, " ", d)); \\ _Harry J. Smith_, Apr 15 2009 + + sage: G = oeis.find_by_id('A27642') # optional -- internet + sage: G.programs('all') # optional -- internet + [('haskell', ...), + ('magma', ...), + ... + ('python', ...), + ('sage', ...)] TESTS:: sage: s = oeis._imaginary_sequence() sage: s.programs() - 0: (Python) - 1: def A999999(n): - 2: assert(isinstance(n, (int, Integer))), "n must be an integer." - 3: if n < 38: - 4: raise ValueError("The value %s is not accepted." %str(n))) - 5: elif n == 42: - 6: return 2 - 7: else: - 8: return 1 - - sage: s.programs('maple') + [('maple', ...), + ('mathematica', ...), + ('python', + 0: def A999999(n): + 1: assert(isinstance(n, (int, Integer))), "n must be an integer." + 2: if n < 38: + 3: raise ValueError("The value %s is not accepted." %str(n)) + 4: elif n == 42: + 5: return 2 + 6: else: + 7: return 1)] + + sage: s.programs('maple')[0] 0: Do not even try, Maple is not able to produce such a sequence. - sage: s.programs('mathematica') + sage: s.programs('mathematica')[0] 0: Mathematica neither. """ + language = language.lower() if language == "maple": - return FancyTuple(self._field('p')) + return [FancyTuple(self._field('p'))] elif language == "mathematica": - return FancyTuple(self._field('t')) + return [FancyTuple(self._field('t'))] + if language == 'sagemath': + language = 'sage' + if language == 'all': + table = [('maple', FancyTuple(self._field('p'))), + ('mathematica', FancyTuple(self._field('t')))] else: - return FancyTuple(self._field('o')) + table = [] + + def is_starting_line(line): + """ + Help to split the big OEIS code block into blocks by language. + + This returns ``None`` if ``line`` is not a starting line. + """ + if not line.startswith('('): + return None + if ')' not in line: + return None + end = line.index(')') + language = line[1:end].lower() # to handle (Sage) versus (sage) + if '(' in language: + return None + if language == 'sagemath': + language = 'sage' + if language == 'c#' or language == 'c++': + language = 'c' + if language.replace(' ', '').isalnum() or language.startswith('scheme'): + # to cope with many wrong (Scheme xxx) separators in the OEIS + return (language, end) + return None + + def filter_sage(lines): + """ + Remove comments and preparse if required, only for sage code. + + This is an iterator. + """ + for line in lines: + if keep_comments or not line.strip().startswith('#'): + if preparsing: + yield preparse(line) + else: + yield line + + def flush_to_table(language, code_lines): + """ + Put a list of code lines into the appropriate box of the table. + + With special treatment for sage code blocks. + """ + if language == 'sage': + table.append((language, FancyTuple(filter_sage(code_lines)))) + elif language is not None: + table.append((language, FancyTuple(code_lines))) + + programs = FancyTuple(self._field('o')) + code_lines = [] + old_language = None + for line in programs: + new_language = is_starting_line(line) + if new_language is not None: + # flush the stock of code lines if any + flush_to_table(old_language, code_lines) + # start new stock of code lines + old_language, end = new_language + rest = line[end + 1:].strip() + code_lines = [rest] if rest else [] + else: + code_lines.append(line) + flush_to_table(old_language, code_lines) + + if language == 'all': + return sorted(table) + return sorted(prog for la, prog in table if la == language) + + def test_compile_sage_code(self): + """ + Try to compile the extracted sage code, if there is any. + + If there are several sage code fields, they are all considered. + + Dead sequences are considered to compile correctly by default. + + This returns ``True`` if the code compiles, and raises an error + otherwise. + + EXAMPLES:: + + sage: s = oeis.find_by_id('A27642') # optional -- internet + sage: s.test_compile_sage_code() # optional -- internet + True + """ + if self.is_dead(): + raise True + filt = self.programs(language='sage') + if filt: + for v in filt: + tp = tmp_filename(ext='.sage') + _ = compile('\n'.join(v), tp, 'exec') + return True class FancyTuple(tuple): From db6e482dd08a2dc21024bc94d0cc4ef45e48685d Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Sat, 9 May 2020 21:29:57 -0600 Subject: [PATCH 166/476] doctest for #19010 --- src/sage/groups/libgap_wrapper.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index d4ad92b6be4..33a50836d04 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -253,6 +253,14 @@ class ParentLibGAP(SageObject): sage: G.subgroup(subgroup_gens) Subgroup with 8 generators of Matrix group over Rational Field with 48 generators + TESTS: + + Check that :trac:`19010` is fixed:: + + sage: G = WeylGroup(['B',3]) + sage: H = G.subgroup([G[14], G[17]]) + sage: all([(g*h in G) and (h*g in G) for g in G for h in H]) + True """ generators = [ g if isinstance(g, GapElement) else self(g).gap() for g in generators ] From 83ddfcd14314b04858618f7cfa2c39208a0f80ef Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Sun, 10 May 2020 02:07:12 -0600 Subject: [PATCH 167/476] reviewer correction --- src/sage/groups/libgap_wrapper.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index 33a50836d04..d06bebe881b 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -259,7 +259,7 @@ class ParentLibGAP(SageObject): sage: G = WeylGroup(['B',3]) sage: H = G.subgroup([G[14], G[17]]) - sage: all([(g*h in G) and (h*g in G) for g in G for h in H]) + sage: all(g*h in G and h*g in G for g in G for h in H) True """ generators = [ g if isinstance(g, GapElement) else self(g).gap() From 8d2c07004fe257328c1a43bc9c6860aa41b6f659 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Sun, 10 May 2020 17:41:05 +0100 Subject: [PATCH 168/476] #29666: fix precision of elliptic curve point height computation --- src/sage/schemes/elliptic_curves/ell_point.py | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index fdd20ab16fd..69a519af208 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -2784,30 +2784,36 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): return h from sage.rings.number_field.number_field import refine_embedding + from sage.all import RealField, ComplexField, Infinity prec_v = v.codomain().prec() if prec is None: prec = prec_v if K is rings.QQ: - vv = K.embeddings(rings.RealField(max(2*prec, prec_v)))[0] - else: - vv = refine_embedding(v, 2*prec) # vv.prec() = max(2*prec, prec_v) + v = K.embeddings(RealField())[0] + v_inf = refine_embedding(v, Infinity) + + v_is_real = v_inf(K.gen()).imag().is_zero() + working_prec = prec+100 + RC = RealField(working_prec) if v_is_real else ComplexField(working_prec) - absdisc = vv(E.discriminant()).abs() - while absdisc==0: - vv = refine_embedding(vv) - # print("doubling precision") - absdisc = vv(E.discriminant()).abs() - temp = 0 if absdisc>=1 else absdisc.log()/3 + # NB We risk losing much precision if we compute the embedding + # of K into RR or CC to some precision and then apply that to + # elements of K. Instead we map elements of K into AA or Qbar + # (with infinite precision) and then trim back to RR or CC. - b2, b4, b6, b8 = [vv(b) for b in E.b_invariants()] - H = max(vv(4), abs(b2), 2*abs(b4), 2*abs(b6), abs(b8)) + x = RC(v_inf(self[0])) + b2, b4, b6, b8 = [RC(v_inf(b)) for b in E.b_invariants()] # The following comes from Silverman Theorem 4.2. Silverman # uses decimal precision d, so his term (5/3)d = # (5/3)*(log(2)/log(10))*prec = 0.5017*prec, which we round # up. The rest of the expression was wrongly transcribed in # Sage versions <5.6 (see #12509). - nterms = int(math.ceil(0.51*prec + 0.5 + 0.75 * (7 + 4*H.log()/3 - temp).log())) + + H = max(RC(4).abs(), b2.abs(), 2*b4.abs(), 2*b6.abs(), b8.abs()) + absdisc = RC(v_inf(E.discriminant())).abs() + adl3 = 0 if absdisc>=1 else absdisc.log()/3 + nterms = int(math.ceil(0.51*working_prec + 0.5 + 0.75 * (7 + 4*H.log()/3 - adl3).log())) b2p = b2 - 12 b4p = b4 - b2 + 6 @@ -2819,7 +2825,6 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): fw = lambda T: T*(4 + T*(b2 + T*(2*b4 + T*b6))) fwp = lambda T: T*(4 + T*(b2p + T*(2*b4p + T*b6p))) - x = vv(self[0]) if abs(x) >= .5: t = 1/x beta = True @@ -2834,7 +2839,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): if beta: w = fw(t) z = fz(t) - if abs(w) <= 2 * abs(z): + if abs(w) <= 2 * z.abs(): mu += four_to_n * z.abs().log() t = w/z else: @@ -2844,7 +2849,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): else: w = fwp(t) z = fzp(t) - if abs(w) <= 2 * abs(z): + if abs(w) <= 2 * z.abs(): mu += four_to_n * z.abs().log() t = w/z else: @@ -2852,8 +2857,9 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): t = w/(z-w) beta = not beta four_to_n >>= 2 - h = rings.RealField(prec)(lam + mu/4) - if weighted and not v.im_gens()[0] in rings.RR: + + h = RealField(prec)(lam + mu/4) + if weighted and not v_is_real: h *= 2 return h From a5c17a86af01597655d6a99d0f2b68793048253d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Mar 2020 20:34:28 -0400 Subject: [PATCH 169/476] build/pkgs/cython: Update to 0.29.16 --- build/pkgs/cython/checksums.ini | 7 ++++--- build/pkgs/cython/package-version.txt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index 7e9b0490f41..6e5583857fd 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -1,4 +1,5 @@ tarball=Cython-VERSION.tar.gz -sha1=1c0c6cb9ebb875e8769863e1720683b24a755a7c -md5=f212574687a52706ff53738a64f91398 -cksum=1612385007 +sha1=5a557bd74d5781c4252675a2805ef2742e88b0cb +md5=a899abaa48b68bb679aef45ceb4b89d3 +cksum=2101179202 +upstream_url=https://files.pythonhosted.org/packages/49/8a/6a4135469372da2e3d9f88f71c6d00d8a07ef65f121eeca0c7ae21697219/Cython-0.29.16.tar.gz diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index fe14ade44a2..a711eb84906 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.12.p0 +0.29.16 From c7cc999e75ebcb3cff0c976cdf8010c8831589f3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Mar 2020 21:58:33 -0400 Subject: [PATCH 170/476] build/pkgs/cython/checksums.ini: Use predictable URL for upstream_url pattern --- build/pkgs/cython/checksums.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index 6e5583857fd..3eb2ff218e6 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -2,4 +2,4 @@ tarball=Cython-VERSION.tar.gz sha1=5a557bd74d5781c4252675a2805ef2742e88b0cb md5=a899abaa48b68bb679aef45ceb4b89d3 cksum=2101179202 -upstream_url=https://files.pythonhosted.org/packages/49/8a/6a4135469372da2e3d9f88f71c6d00d8a07ef65f121eeca0c7ae21697219/Cython-0.29.16.tar.gz +upstream_url=https://pypi.io/packages/source/C/Cython/Cython-VERSION.tar.gz From d54b715814ca3dfb8f5c6421f3a101e30bf14945 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 May 2020 13:02:37 -0700 Subject: [PATCH 171/476] Update Cython to 0.29.17 --- build/pkgs/cython/checksums.ini | 6 +++--- build/pkgs/cython/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index 3eb2ff218e6..93cd5fb718a 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -1,5 +1,5 @@ tarball=Cython-VERSION.tar.gz -sha1=5a557bd74d5781c4252675a2805ef2742e88b0cb -md5=a899abaa48b68bb679aef45ceb4b89d3 -cksum=2101179202 +sha1=02278e5a972ffc4856451f507903db68d08cfd6e +md5=0936311ccd09f1164ab2f46ca5cd8c3b +cksum=1144843552 upstream_url=https://pypi.io/packages/source/C/Cython/Cython-VERSION.tar.gz diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index a711eb84906..9fe45285805 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.16 +0.29.17 From 17c5712695c544a8973ba462f3cace6f8663b7b9 Mon Sep 17 00:00:00 2001 From: John Cremona Date: Mon, 11 May 2020 12:18:40 +0100 Subject: [PATCH 172/476] #29666: further minor improvement and added doctest --- src/sage/schemes/elliptic_curves/ell_point.py | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 69a519af208..ff4d5b68baf 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -2755,7 +2755,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): sage: E = EllipticCurve(v) sage: P = E([72*a - 509/5, -682/25*a - 434/25]) sage: P.archimedean_local_height() - -0.2206607955468278492183362746930 + -0.220660795546828 See :trac:`19276`:: @@ -2763,28 +2763,46 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): sage: E = EllipticCurve([1, a - 1, 1, -816765673272*a - 7931030674178, 1478955604013312315*a + 14361086227143654561]) sage: P = E(5393511/49*a + 52372721/49 , -33896210324/343*a - 329141996591/343 ) sage: P.height() - 0.974232017827740 + 0.974232017827741 + + See :trac:`29966`:: + + sage: K. = NumberField(x^3 - x^2 - 6*x + 2) + sage: E = EllipticCurve([1, -a^2 + 2*a + 4, 0, -6056450500590472699700624*a^2 - 11239394326797569935861742*a + 4241549693833829432516231, 1904879037869682826729875958079326124520*a^2 + 3535022146945771697732350459284777382011*a - 1334055169621036218710397707677347972626]) + sage: P = E([1033399668533*a^2 + 1917754693229*a - 723726883800 , 12536493059202326563*a^2 + 23264879148900575548*a - 8779756111574815918 , 1]) + sage: P.height() + 0.297318833424763 + sage: (2*P).height() / P.height() + 4.00000000000000 + sage: P.height(200) + 0.29731883342476341806143743594519935578696537745294661858984 + sage: (2*P).height(200) / P.height(200) + 4.0000000000000000000000000000000000000000000000000000000000 """ + from sage.rings.number_field.number_field import refine_embedding + from sage.all import RealField, ComplexField, Infinity + E = self.curve() K = E.base_ring() if v is None: + + if prec is None: + prec = 53 if K is rings.QQ: v = K.embeddings(rings.RR)[0] - h = self.archimedean_local_height(v, prec) + h = self.archimedean_local_height(v, prec+10) else: r1, r2 = K.signature() pl = K.places() - h = (sum(self.archimedean_local_height(pl[i], prec, weighted=False) + h = (sum(self.archimedean_local_height(pl[i], prec+10, weighted=False) for i in range(r1)) - + 2 * sum(self.archimedean_local_height(pl[i], prec, weighted=False) + + 2 * sum(self.archimedean_local_height(pl[i], prec+10, weighted=False) for i in range(r1, r1 + r2))) if not weighted: h /= K.degree() - return h + return RealField(prec)(h) - from sage.rings.number_field.number_field import refine_embedding - from sage.all import RealField, ComplexField, Infinity prec_v = v.codomain().prec() if prec is None: prec = prec_v From 80766a2318b6580d903af490f913ce6a6552e9f4 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Sat, 25 Apr 2020 22:59:55 +0200 Subject: [PATCH 173/476] set up product with both Vrep and Hrep --- src/sage/geometry/polyhedron/base.py | 50 ++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 01989bbd80e..c3eb81e48e8 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -4356,6 +4356,17 @@ def product(self, other): 'ppl' sage: (P * polytopes.dodecahedron(backend='field')).backend() 'field' + + Check that double description is set up correctly:: + + sage: P = polytopes.permutahedron(4).base_extend(QQ) + sage: P1 = Polyhedron(rays=[[1,0,0,0],[0,1,1,0]], lines=[[0,1,0,1]]) + sage: Q = P.base_extend(QQ, 'field') + sage: Q1 = P1.base_extend(QQ, 'field') + sage: P*P1 == Q*Q1 + True + sage: P.polar(in_affine_span=True)*P1 == Q.polar(in_affine_span=True)*Q1 + True """ try: new_ring = self.parent()._coerce_base_ring(other) @@ -4363,21 +4374,34 @@ def product(self, other): raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) \ + " and " + str(other.parent())) - new_vertices = [ list(x)+list(y) - for x in self.vertex_generator() for y in other.vertex_generator()] - new_rays = [] - new_rays.extend( [ r+[0]*other.ambient_dim() - for r in self.ray_generator() ] ) - new_rays.extend( [ [0]*self.ambient_dim()+r - for r in other.ray_generator() ] ) - new_lines = [] - new_lines.extend( [ l+[0]*other.ambient_dim() - for l in self.line_generator() ] ) - new_lines.extend( [ [0]*self.ambient_dim()+l - for l in other.line_generator() ] ) + from itertools import chain + + new_vertices = (tuple(x)+tuple(y) + for x in self.vertex_generator() for y in other.vertex_generator()) + + self_zero = tuple(0 for _ in range( self.ambient_dim())) + other_zero = tuple(0 for _ in range(other.ambient_dim())) + + rays = chain((tuple(r) + other_zero for r in self.ray_generator()), + (self_zero + tuple(r) for r in other.ray_generator())) + + lines = chain((tuple(l) + other_zero for l in self.line_generator()), + (self_zero + tuple(l) for l in other.line_generator())) + + ieqs = chain((tuple(i) + other_zero for i in self.inequality_generator()), + ((i.b(),) + self_zero + tuple(i.A()) for i in other.inequality_generator())) + + eqns = chain((tuple(e) + other_zero for e in self.equation_generator()), + ((e.b(),) + self_zero + tuple(e.A()) for e in other.equation_generator())) + + + pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() + other.n_vertices() + other.n_rays() \ + <= self.n_inequalities() + other.n_inequalities() else 'Hrep' parent = self.parent().change_ring(new_ring, ambient_dim=self.ambient_dim() + other.ambient_dim()) - return parent.element_class(parent, [new_vertices, new_rays, new_lines], None) + return parent.element_class(parent, [new_vertices, rays, lines], + [ieqs, eqns], + Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) _mul_ = product From bda2219713aef3dce503111aa17b553215cd2823 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 May 2020 17:14:41 +0200 Subject: [PATCH 174/476] spaces between binary operators --- src/sage/geometry/polyhedron/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index c3eb81e48e8..12143c7bd38 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -4363,9 +4363,9 @@ def product(self, other): sage: P1 = Polyhedron(rays=[[1,0,0,0],[0,1,1,0]], lines=[[0,1,0,1]]) sage: Q = P.base_extend(QQ, 'field') sage: Q1 = P1.base_extend(QQ, 'field') - sage: P*P1 == Q*Q1 + sage: P * P1 == Q * Q1 True - sage: P.polar(in_affine_span=True)*P1 == Q.polar(in_affine_span=True)*Q1 + sage: P.polar(in_affine_span=True) * P1 == Q.polar(in_affine_span=True) * Q1 True """ try: @@ -4376,7 +4376,7 @@ def product(self, other): from itertools import chain - new_vertices = (tuple(x)+tuple(y) + new_vertices = (tuple(x) + tuple(y) for x in self.vertex_generator() for y in other.vertex_generator()) self_zero = tuple(0 for _ in range( self.ambient_dim())) From b4ec8dea6bfca5a98095af0b764db3b1790e45e3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 May 2020 17:22:51 +0200 Subject: [PATCH 175/476] coding style --- src/sage/geometry/polyhedron/base.py | 69 +++++++++++++++++----------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 12143c7bd38..72f88f74683 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1028,22 +1028,32 @@ def _repr_(self): if self.n_vertices() > 0: desc += ' defined as the convex hull of ' desc += repr(self.n_vertices()) - if self.n_vertices() == 1: desc += ' vertex' - else: desc += ' vertices' + if self.n_vertices() == 1: + desc += ' vertex' + else: + desc += ' vertices' if self.n_rays() > 0: - if self.n_lines() > 0: desc += ", " - else: desc += " and " + if self.n_lines() > 0: + desc += ", " + else: + desc += " and " desc += repr(self.n_rays()) - if self.n_rays() == 1: desc += ' ray' - else: desc += ' rays' + if self.n_rays() == 1: + desc += ' ray' + else: + desc += ' rays' if self.n_lines() > 0: - if self.n_rays() > 0: desc += ", " - else: desc += " and " + if self.n_rays() > 0: + desc += ", " + else: + desc += " and " desc += repr(self.n_lines()) - if self.n_lines() == 1: desc += ' line' - else: desc += ' lines' + if self.n_lines() == 1: + desc += ' line' + else: + desc += ' lines' return desc @@ -2225,10 +2235,13 @@ def bounded_edges(self): """ obj = self.Vrepresentation() for i in range(len(obj)): - if not obj[i].is_vertex(): continue + if not obj[i].is_vertex(): + continue for j in range(i+1, len(obj)): - if not obj[j].is_vertex(): continue - if self.vertex_adjacency_matrix()[i, j] == 0: continue + if not obj[j].is_vertex(): + continue + if self.vertex_adjacency_matrix()[i, j] == 0: + continue yield (obj[i], obj[j]) def Vrepresentation_space(self): @@ -3702,7 +3715,8 @@ def gale_transform(self): sage: sum(P.gale_transform()).norm() < 1e-15 True """ - if not self.is_compact(): raise ValueError('not a polytope') + if not self.is_compact(): + raise ValueError('not a polytope') A = matrix(self.n_vertices(), [ [1]+x for x in self.vertex_generator()]) @@ -6951,11 +6965,11 @@ def _volume_lrs(self, verbose=False): EXAMPLES:: - sage: polytopes.hypercube(3)._volume_lrs() #optional - lrslib + sage: polytopes.hypercube(3)._volume_lrs() # optional - lrslib 8.0 - sage: (polytopes.hypercube(3)*2)._volume_lrs() #optional - lrslib + sage: (polytopes.hypercube(3)*2)._volume_lrs() # optional - lrslib 64.0 - sage: polytopes.twenty_four_cell()._volume_lrs() #optional - lrslib + sage: polytopes.twenty_four_cell()._volume_lrs() # optional - lrslib 2.0 REFERENCES: @@ -6974,7 +6988,8 @@ def _volume_lrs(self, verbose=False): in_file = open(in_filename, 'w') in_file.write(in_str) in_file.close() - if verbose: print(in_str) + if verbose: + print(in_str) lrs_procs = Popen(['lrs', in_filename], stdin=PIPE, stdout=PIPE, stderr=PIPE) @@ -7021,30 +7036,30 @@ def _volume_latte(self, verbose=False, algorithm='triangulate', **kwargs): EXAMPLES:: - sage: polytopes.hypercube(3)._volume_latte() #optional - latte_int + sage: polytopes.hypercube(3)._volume_latte() # optional - latte_int 8 - sage: (polytopes.hypercube(3)*2)._volume_latte() #optional - latte_int + sage: (polytopes.hypercube(3)*2)._volume_latte() # optional - latte_int 64 - sage: polytopes.twenty_four_cell()._volume_latte() #optional - latte_int + sage: polytopes.twenty_four_cell()._volume_latte() # optional - latte_int 2 - sage: polytopes.cuboctahedron()._volume_latte() #optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte() # optional - latte_int 20/3 TESTS: Testing triangulate algorithm:: - sage: polytopes.cuboctahedron()._volume_latte(algorithm='triangulate') #optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(algorithm='triangulate') # optional - latte_int 20/3 Testing cone decomposition algorithm:: - sage: polytopes.cuboctahedron()._volume_latte(algorithm='cone-decompose') #optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(algorithm='cone-decompose') # optional - latte_int 20/3 Testing raw output:: - sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) #optional - latte_int + sage: polytopes.cuboctahedron()._volume_latte(raw_output=True) # optional - latte_int '20/3' Testing inexact rings:: @@ -7137,10 +7152,10 @@ def volume(self, measure='ambient', engine='auto', **kwds): reasons, Sage casts lrs's exact answer to a float:: sage: I3 = polytopes.hypercube(3) - sage: I3.volume(engine='lrs') #optional - lrslib + sage: I3.volume(engine='lrs') # optional - lrslib 8.0 sage: C24 = polytopes.twenty_four_cell() - sage: C24.volume(engine='lrs') #optional - lrslib + sage: C24.volume(engine='lrs') # optional - lrslib 2.0 If the base ring is exact, the answer is exact:: From 8802873fc4ba4e6d2e17acd092d75bc4357dd4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Tue, 12 May 2020 12:12:32 +0200 Subject: [PATCH 176/476] Forgot 1 pyflake --- src/sage/geometry/polyhedron/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 72f88f74683..b3eb1441a8e 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -3268,7 +3268,8 @@ def is_simple(self): False """ - if not self.is_compact(): return False + if not self.is_compact(): + return False return self.combinatorial_polyhedron().is_simple() def simpliciality(self): From dfb3144ac1aeef57e97aa4ac6e5b4f710d1d118b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Tue, 12 May 2020 12:33:11 +0200 Subject: [PATCH 177/476] More pep8 --- src/sage/geometry/polyhedron/base.py | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index b3eb1441a8e..0281edad992 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1573,7 +1573,7 @@ def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=Non if align is None: align = separator == "\n" if align: - lengths = [(len(s[0]), len(s[1]), len(s[2])) for s in pretty_hs] + lengths = [(len(s[0]), len(s[1]), len(s[2])) for s in pretty_hs] from operator import itemgetter length_left = max(lengths, key=itemgetter(0))[0] length_middle = max(lengths, key=itemgetter(1))[1] @@ -2089,7 +2089,7 @@ def an_affine_basis(self): # We use in the following that elements in ``chain_indices`` are sorted lists # of V-indices. # Thus for each two faces we can easily find the first vertex that differs. - for dim,face in enumerate(chain_indices): + for dim, face in enumerate(chain_indices): if dim == 0: # Append the vertex. basis_indices.append(face[0]) @@ -2547,7 +2547,7 @@ def boundary_complex(self): ineq_indices = [inc_mat_cols[i].nonzero_positions() for i in range(self.n_Hrepresentation()) if self.Hrepresentation()[i].is_inequality()] - return SimplicialComplex(ineq_indices,maximality_check=False) + return SimplicialComplex(ineq_indices, maximality_check=False) else: raise NotImplementedError("this function is only implemented for simplicial polytopes") @@ -2678,10 +2678,10 @@ def incidence_matrix(self): incidence_matrix = matrix(ZZ, self.n_Vrepresentation(), self.n_Hrepresentation(), 0) - Vvectors_vertices = tuple((v.vector(),v.index()) + Vvectors_vertices = tuple((v.vector(), v.index()) for v in self.Vrep_generator() if v.is_vertex()) - Vvectors_rays_lines = tuple((v.vector(),v.index()) + Vvectors_rays_lines = tuple((v.vector(), v.index()) for v in self.Vrep_generator() if not v.is_vertex()) @@ -2691,13 +2691,13 @@ def incidence_matrix(self): Hindex = H.index() for Vvec, Vindex in Vvectors_vertices: if self._is_zero(Hvec*Vvec + Hconst): - incidence_matrix[Vindex, Hindex] = 1 + incidence_matrix[Vindex, Hindex] = 1 # A ray or line is considered incident with a hyperplane, # if it is orthogonal to the normal vector of the hyperplane. for Vvec, Vindex in Vvectors_rays_lines: if self._is_zero(Hvec*Vvec): - incidence_matrix[Vindex, Hindex] = 1 + incidence_matrix[Vindex, Hindex] = 1 incidence_matrix.set_immutable() return incidence_matrix @@ -2868,11 +2868,11 @@ def centroid(self, engine='auto', **kwds): pc = triangulation.point_configuration() else: from sage.geometry.triangulation.point_configuration import PointConfiguration - A,b = self.affine_hull_projection(as_affine_map=True, orthogonal=True, orthonormal=True, extend=True) + A, b = self.affine_hull_projection(as_affine_map=True, orthogonal=True, orthonormal=True, extend=True) pc = PointConfiguration((A(v.vector()) for v in self.Vrep_generator())) barycenters = [sum(self.Vrepresentation(i).vector() for i in simplex)/(self.dim() + 1) for simplex in triangulation] - volumes = [pc.volume(simplex) for simplex in triangulation] + volumes = [pc.volume(simplex) for simplex in triangulation] centroid = sum(volumes[i]*barycenters[i] for i in range(len(volumes)))/sum(volumes) if self.ambient_dim() != self.dim(): @@ -3629,7 +3629,7 @@ def is_prism(self, certificate=False): # We have found two candidates for base faces. # Remove from each vertex ``index1`` resp. ``index2``. test_verts = set(frozenset(vert_inc.difference({index1, index2})) - for vert_inc in verts_incidences) + for vert_inc in verts_incidences) if len(test_verts) == n_verts/2: # For each vertex containing `index1` there is # another one contained in `index2` @@ -3720,7 +3720,7 @@ def gale_transform(self): raise ValueError('not a polytope') A = matrix(self.n_vertices(), - [ [1]+x for x in self.vertex_generator()]) + [[1]+x for x in self.vertex_generator()]) A = A.transpose() A_ker = A.right_kernel_matrix(basis='computed') return tuple(A_ker.columns()) @@ -4386,8 +4386,8 @@ def product(self, other): try: new_ring = self.parent()._coerce_base_ring(other) except TypeError: - raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) \ - + " and " + str(other.parent())) + raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) + + " and " + str(other.parent())) from itertools import chain @@ -4409,7 +4409,6 @@ def product(self, other): eqns = chain((tuple(e) + other_zero for e in self.equation_generator()), ((e.b(),) + self_zero + tuple(e.A()) for e in other.equation_generator())) - pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() + other.n_vertices() + other.n_rays() \ <= self.n_inequalities() + other.n_inequalities() else 'Hrep' @@ -4704,8 +4703,8 @@ def dilation(self, scalar): one = parent.base_ring().one() sign = one if scalar > 0 else -one - make_new_Hrep = lambda h : tuple(scalar*sign*x if i == 0 else sign*x - for i,x in enumerate(h._vector)) + make_new_Hrep = lambda h: tuple(scalar*sign*x if i == 0 else sign*x + for i, x in enumerate(h._vector)) new_vertices = (tuple(scalar*x for x in v._vector) for v in self.vertex_generator()) new_rays = (tuple(sign*x for x in r._vector) for r in self.ray_generator()) @@ -5195,8 +5194,8 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): normal_vectors.append(facet.A()) if linear_coefficients is not None: - normal_vector = sum(linear_coefficients[i]*normal_vectors[i] for i - in range(len(normal_vectors))) + normal_vector = sum(linear_coefficients[i]*normal_vectors[i] + for i in range(len(normal_vectors))) else: normal_vector = sum(normal_vectors) @@ -5570,7 +5569,7 @@ def lawrence_extension(self, v): raise ValueError("{} must not be a vertex or outside self".format(v)) lambda_V = [u + [0] for u in V if u != v] + [v+[1]] + [v+[2]] - parent = self.parent().change_ring(self.base_ring(), ambient_dim = self.ambient_dim() + 1) + parent = self.parent().change_ring(self.base_ring(), ambient_dim=self.ambient_dim()+1) return parent.element_class(parent, [lambda_V, [], []], None) def lawrence_polytope(self): @@ -5632,7 +5631,7 @@ def lawrence_polytope(self): n = self.n_vertices() I_n = matrix.identity(n) lambda_V = block_matrix([[V, I_n], [V, 2*I_n]]) - parent = self.parent().change_ring(self.base_ring(), ambient_dim = self.ambient_dim() + n) + parent = self.parent().change_ring(self.base_ring(), ambient_dim=self.ambient_dim()+n) return parent.element_class(parent, [lambda_V, [], []], None) def is_lawrence_polytope(self): @@ -5944,9 +5943,9 @@ def face_constructor(atoms, coatoms): if not atoms: Vindices = () else: - Vindices = tuple(sorted([ atom_to_Vindex[i] for i in atoms ]+lines)) - Hindices = tuple(sorted([ coatom_to_Hindex[i] for i in coatoms ]+equations)) - return PolyhedronFace(self,Vindices, Hindices) + Vindices = tuple(sorted([atom_to_Vindex[i] for i in atoms] + lines)) + Hindices = tuple(sorted([coatom_to_Hindex[i] for i in coatoms] + equations)) + return PolyhedronFace(self, Vindices, Hindices) from sage.geometry.hasse_diagram import lattice_from_incidences return lattice_from_incidences(atoms_incidences, coatoms_incidences, @@ -6950,7 +6949,7 @@ def schlegel_projection(self, projection_dir=None, height=1.1): if projection_dir is None: vertices = self.vertices() facet = self.Hrepresentation(0) - f0 = [ v.index() for v in facet.incident() ] + f0 = [v.index() for v in facet.incident()] projection_dir = [sum([vertices[f0[i]][j]/len(f0) for i in range(len(f0))]) for j in range(self.ambient_dim())] return proj.schlegel(projection_direction=projection_dir, height=height) @@ -8070,7 +8069,7 @@ def bounding_box(self, integral=False, integral_hull=False): if self.n_vertices() == 0: raise ValueError("empty polytope is not allowed") for i in range(self.ambient_dim()): - coords = [ v[i] for v in self.vertex_generator() ] + coords = [v[i] for v in self.vertex_generator()] max_coord = max(coords) min_coord = min(coords) if integral_hull: @@ -8262,7 +8261,7 @@ def integral_points(self, threshold=100000): triangulation = self.triangulate() points = set() for simplex in triangulation: - triang_vertices = [ self.Vrepresentation(i) for i in simplex ] + triang_vertices = [self.Vrepresentation(i) for i in simplex] new_points = simplex_points(triang_vertices) for p in new_points: p.set_immutable() @@ -8794,6 +8793,7 @@ def rational_approximation(c): return c else: c_list = [] + def rational_approximation(c): # Implementation detail: Return unique integer if two # c-values are the same up to machine precision. But From 6c9e848e542b08660bf633293fc0155bef6c3304 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 12 May 2020 17:37:27 +0200 Subject: [PATCH 178/476] cleanup of 28757 --- .../bit_vector_operations.pxd | 63 ------------------- .../polyhedron_face_lattice.pyx | 5 +- 2 files changed, 2 insertions(+), 66 deletions(-) delete mode 100644 src/sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.pxd diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.pxd deleted file mode 100644 index ad4e8dd129d..00000000000 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.pxd +++ /dev/null @@ -1,63 +0,0 @@ -# distutils: language = c++ - -cimport cython -from libc.stdint cimport uint64_t - -cdef extern from "bit_vector_operations.cc": - # Any Bit-representation is assumed to be `chunksize`-Bit aligned. - cdef const size_t chunksize - cdef void intersection(uint64_t *A, uint64_t *B, uint64_t *C, - size_t face_length) -# Return ``A & ~B == 0``. -# A is not subset of B, iff there is a vertex in A, which is not in B. -# ``face_length`` is the length of A and B in terms of uint64_t. - - cdef size_t get_next_level( - uint64_t **faces, const size_t n_faces, uint64_t **nextfaces, - uint64_t **nextfaces2, uint64_t **visited_all, - size_t n_visited_all, size_t face_length) -# Set ``newfaces`` to be the facets of ``faces[n_faces -1]`` -# that are not contained in a face of ``visited_all``. - -# INPUT: - -# - ``maybe_newfaces`` -- quasi of type ``uint64_t[n_faces -1][face_length]``, -# needs to be ``chunksize``-Bit aligned -# - ``newfaces`` -- quasi of type ``*uint64_t[n_faces -1] -# - ``visited_all`` -- quasi of type ``*uint64_t[n_visited_all] -# - ``face_length`` -- length of the faces - -# OUTPUT: - -# - return number of ``newfaces`` -# - set ``newfaces`` to point to the new faces - -# ALGORITHM: - -# To get all facets of ``faces[n_faces-1]``, we would have to: -# - Intersect the first ``n_faces-1`` faces of ``faces`` with the last face. -# - Add all the intersection of ``visited_all`` with the last face -# - Out of both the inclusion-maximal ones are of codimension 1, i.e. facets. - -# As we have visited all faces of ``visited_all``, we alter the algorithm -# to not revisit: -# Step 1: Intersect the first ``n_faces-1`` faces of ``faces`` with the last face. -# Step 2: Out of thosse the inclusion-maximal ones are some of the facets. -# At least we obtain all of those, that we have not already visited. -# Maybe, we get some more. -# Step 3: Only keep those that we have not already visited. -# We obtain exactly the facets of ``faces[n_faces-1]`` that we have -# not visited yet. - - cdef size_t count_atoms(uint64_t *A, size_t face_length) -# Return the number of atoms/vertices in A. -# This is the number of set bits in A. -# ``face_length`` is the length of A in terms of uint64_t. - - cdef size_t bit_rep_to_coatom_rep( - uint64_t *face, uint64_t **coatoms, size_t n_coatoms, - size_t face_length, size_t *output) -# Write the coatom-representation of face in output. Return length. -# ``face_length`` is the length of ``face`` and ``coatoms[i]`` -# in terms of uint64_t. -# ``n_coatoms`` length of ``coatoms``. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index f7af68746e5..26fb1da4257 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -72,9 +72,8 @@ from .face_iterator cimport FaceIterator cdef extern from "bit_vector_operations.cc": cdef void intersection(uint64_t *A, uint64_t *B, uint64_t *C, size_t face_length) -# Return ``A & ~B == 0``. -# A is not subset of B, iff there is a vertex in A, which is not in B. -# ``face_length`` is the length of A and B in terms of uint64_t. +# Set ``C = A & B``, i.e. C is the intersection of A and B. +# ``face_length`` is the length of A, B and C in terms of uint64_t. cdef size_t bit_rep_to_coatom_rep( uint64_t *face, uint64_t **coatoms, size_t n_coatoms, From 4ec5aacd326c453458c87fea31f58d86886a20ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 May 2020 10:21:59 +0200 Subject: [PATCH 179/476] spring cleanup for pushout.py --- src/sage/categories/pushout.py | 272 +++++++++++++++++---------------- 1 file changed, 142 insertions(+), 130 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 27e436c6360..573411d772e 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2,7 +2,6 @@ Coercion via construction functors """ from __future__ import print_function, absolute_import -from six.moves import range import six from sage.misc.lazy_import import lazy_import @@ -129,9 +128,9 @@ def __mul__(self, other): """ if not isinstance(self, ConstructionFunctor) and not isinstance(other, ConstructionFunctor): raise CoercionException("Non-constructive product") - if isinstance(other,IdentityConstructionFunctor): + if isinstance(other, IdentityConstructionFunctor): return self - if isinstance(self,IdentityConstructionFunctor): + if isinstance(self, IdentityConstructionFunctor): return other return CompositeConstructionFunctor(other, self) @@ -235,7 +234,7 @@ def _repr_(self): def merge(self, other): """ - Merge ``self`` with another construction functor, or return None. + Merge ``self`` with another construction functor, or return ̀̀None``. .. NOTE:: @@ -532,7 +531,7 @@ def __mul__(self, other): """ if isinstance(self, CompositeConstructionFunctor): all = [other] + self.all - elif isinstance(other,IdentityConstructionFunctor): + elif isinstance(other, IdentityConstructionFunctor): return self else: all = other.all + [self] @@ -550,7 +549,7 @@ def _repr_(self): """ s = "..." for c in self.all: - s = "%s(%s)" % (c,s) + s = "%s(%s)" % (c, s) return s def expand(self): @@ -646,7 +645,6 @@ def __eq__(self, other): """ c = (type(self) == type(other)) if not c: - from sage.categories.functor import IdentityFunctor_generic if isinstance(other, IdentityFunctor_generic): return True return c @@ -921,7 +919,7 @@ def __ne__(self, other): def merge(self, other): """ - Merge ``self`` with another construction functor, or return None. + Merge ``self`` with another construction functor, or return ``None``. NOTE: @@ -1076,7 +1074,7 @@ def __mul__(self, other): sage: G*F MPoly[x,y,t] """ - if isinstance(other,IdentityConstructionFunctor): + if isinstance(other, IdentityConstructionFunctor): return self if isinstance(other, MultiPolynomialFunctor): if self.term_order != other.term_order: @@ -1084,15 +1082,15 @@ def __mul__(self, other): if set(self.vars).intersection(other.vars): raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return MultiPolynomialFunctor(other.vars + self.vars, self.term_order) - elif isinstance(other, CompositeConstructionFunctor) \ - and isinstance(other.all[-1], MultiPolynomialFunctor): + elif (isinstance(other, CompositeConstructionFunctor) + and isinstance(other.all[-1], MultiPolynomialFunctor)): return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) else: return CompositeConstructionFunctor(other, self) def merge(self, other): """ - Merge ``self`` with another construction functor, or return None. + Merge ``self`` with another construction functor, or return ``None``. EXAMPLES:: @@ -1251,7 +1249,7 @@ def __init__(self, gens, order, implementation): True """ - if len(gens)<1: + if not gens: raise ValueError("Infinite Polynomial Rings have at least one generator") ConstructionFunctor.__init__(self, Rings(), Rings()) self._gens = tuple(gens) @@ -1298,7 +1296,7 @@ def _repr_(self): InfPoly{[a,b,x], "degrevlex", "sparse"} """ - return 'InfPoly{[%s], "%s", "%s"}'%(','.join(self._gens), self._order, self._imple) + return 'InfPoly{[%s], "%s", "%s"}' % (','.join(self._gens), self._order, self._imple) def __eq__(self, other): """ @@ -1360,7 +1358,7 @@ def __mul__(self, other): InfPoly{[x,y], "degrevlex", "dense"}(FractionField(...)) """ - if isinstance(other,IdentityConstructionFunctor): + if isinstance(other, IdentityConstructionFunctor): return self if isinstance(other, self.__class__): # INT = set(self._gens).intersection(other._gens) @@ -1400,7 +1398,7 @@ def __mul__(self, other): BadOverlap = False for x in othervars: if x.count('_') == 1: - g,n = x.split('_') + g, n = x.split('_') if n.isdigit(): if g.isalnum(): # we can interprete x in any InfinitePolynomialRing if g in self._gens: # we can interprete x in self, hence, we will not use it as a variable anymore. @@ -1408,12 +1406,12 @@ def __mul__(self, other): IsOverlap = True # some variables of other can be interpreted in self. if OverlappingVars: # Is OverlappingVars in the right order? - g0,n0 = OverlappingVars[-1].split('_') + g0, n0 = OverlappingVars[-1].split('_') i = self._gens.index(g) i0 = self._gens.index(g0) - if iint(n0): # wrong order + if i == i0 and int(n) > int(n0): # wrong order BadOverlap = True OverlappingVars.append(x) else: @@ -1431,18 +1429,18 @@ def __mul__(self, other): if BadOverlap: # the overlapping variables appear in the wrong order raise CoercionException("Overlapping variables (%s,%s) are incompatible" % (self._gens, OverlappingVars)) - if len(OverlappingVars)>1: # multivariate, hence, the term order matters - if other.term_order.name()!=self._order: + if len(OverlappingVars) > 1: # multivariate, hence, the term order matters + if other.term_order.name() != self._order: raise CoercionException("Incompatible term orders %s, %s" % (self._order, other.term_order.name())) # ok, the overlap is fine, we will return something. if RemainingVars: # we can only partially merge other into self - if len(RemainingVars)>1: - return CompositeConstructionFunctor(MultiPolynomialFunctor(RemainingVars,term_order=other.term_order), self) + if len(RemainingVars) > 1: + return CompositeConstructionFunctor(MultiPolynomialFunctor(RemainingVars, term_order=other.term_order), self) return CompositeConstructionFunctor(PolynomialFunctor(RemainingVars[0]), self) return self return CompositeConstructionFunctor(other, self) - def merge(self,other): + def merge(self, other): """ Merge two construction functors of infinite polynomial rings, regardless of monomial order and implementation. @@ -1475,13 +1473,13 @@ def merge(self,other): return self return None try: - OUT = self*other + OUT = self * other # The following happens if "other" has the same order type etc. if not isinstance(OUT, CompositeConstructionFunctor): return OUT except CoercionException: pass - if isinstance(other,InfinitePolynomialFunctor): + if isinstance(other, InfinitePolynomialFunctor): # We don't require that the orders coincide. This is a difference to self*other # We only merge if other's generators are an ordered subset of self's generators for g in other._gens: @@ -1489,7 +1487,7 @@ def merge(self,other): return None # The sequence of variables is part of the ordering. It must coincide in both rings Ind = [self._gens.index(g) for g in other._gens] - if sorted(Ind)!=Ind: + if sorted(Ind) != Ind: return None # OK, other merges into self. Now, choose the default dense implementation, # unless both functors refer to the sparse implementation @@ -1635,6 +1633,7 @@ def __ne__(self, other): def merge(self, other): """ Merging is only happening if both functors are matrix functors of the same dimension. + The result is sparse if and only if both given functors are sparse. EXAMPLES:: @@ -1715,7 +1714,7 @@ def __init__(self, var, multi_variate=False): """ Functor.__init__(self, Rings(), Rings()) - if not isinstance(var, (six.string_types,tuple,list)): + if not isinstance(var, (six.string_types, tuple, list)): raise TypeError("variable name or list of variable names expected") self.var = var self.multi_variate = multi_variate or not isinstance(var, six.string_types) @@ -1791,6 +1790,7 @@ def __ne__(self, other): def merge(self, other): """ Two Laurent polynomial construction functors merge if the variable names coincide. + The result is multivariate if one of the arguments is multivariate. EXAMPLES:: @@ -1860,7 +1860,7 @@ def __init__(self, n, is_sparse=False, inner_product_matrix=None): """ # Functor.__init__(self, Rings(), FreeModules()) # FreeModules() takes a base ring # Functor.__init__(self, Objects(), Objects()) # Object() makes no sense, since FreeModule raises an error, e.g., on Set(['a',1]). - ## FreeModule requires a commutative ring. Thus, we have + # FreeModule requires a commutative ring. Thus, we have Functor.__init__(self, CommutativeRings(), CommutativeAdditiveGroups()) self.n = n self.is_sparse = is_sparse @@ -1908,7 +1908,7 @@ def _apply_functor_to_morphism(self, f): ... NotImplementedError: Can not create induced morphisms of free modules yet """ - ## TODO: Implement this! + # TODO: Implement this! raise NotImplementedError("Can not create induced morphisms of free modules yet") def __eq__(self, other): @@ -1928,7 +1928,8 @@ def __eq__(self, other): True """ if isinstance(other, VectorFunctor): - return (self.n == other.n and self.inner_product_matrix==other.inner_product_matrix) + return (self.n == other.n and + self.inner_product_matrix == other.inner_product_matrix) return False def __ne__(self, other): @@ -2064,11 +2065,11 @@ def __init__(self, basis): [1 2 3] [4 0 1] """ -## Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring -## Functor.__init__(self, Objects(), Objects()) # is too general - ## It seems that the category of commutative additive groups - ## currently is the smallest base ring free category that - ## contains in- and output +# Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring +# Functor.__init__(self, Objects(), Objects()) # is too general + # It seems that the category of commutative additive groups + # currently is the smallest base ring free category that + # contains in- and output Functor.__init__(self, CommutativeAdditiveGroups(), CommutativeAdditiveGroups()) self.basis = basis @@ -2239,7 +2240,8 @@ def merge(self, other): if not self.basis: return other try: - P = pushout(self.basis[0].parent().ambient_module(),other.basis[0].parent().ambient_module()) + P = pushout(self.basis[0].parent().ambient_module(), + other.basis[0].parent().ambient_module()) except CoercionException: return None try: @@ -2248,7 +2250,7 @@ def merge(self, other): submodule = P.span except AttributeError: return None - S = submodule(self.basis+other.basis).echelonized_basis() + S = submodule(self.basis + other.basis).echelonized_basis() return SubspaceFunctor(S) else: return None @@ -2402,10 +2404,10 @@ def __init__(self, p, prec, extras=None): from sage.rings.infinity import Infinity if self.p == Infinity: if self.type not in self._real_types: - raise ValueError("completion type must be one of %s"%(", ".join(self._real_types))) + raise ValueError("completion type must be one of %s" % (", ".join(self._real_types))) else: if self.type not in self._dvr_types: - raise ValueError("completion type must be one of %s"%(", ".join(self._dvr_types[1:]))) + raise ValueError("completion type must be one of %s" % (", ".join(self._dvr_types[1:]))) def _repr_(self): """ @@ -2434,28 +2436,28 @@ def _apply_functor(self, R): """ try: - if len(self.extras) == 0: + if not self.extras: if self.type is None: try: return R.completion(self.p, self.prec) except TypeError: return R.completion(self.p, self.prec, {}) else: - return R.completion(self.p, self.prec, {'type':self.type}) + return R.completion(self.p, self.prec, {'type': self.type}) else: extras = self.extras.copy() extras['type'] = self.type return R.completion(self.p, self.prec, extras) - except (NotImplementedError,AttributeError): + except (NotImplementedError, AttributeError): if R.construction() is None: - raise NotImplementedError("Completion is not implemented for %s"%R.__class__) + raise NotImplementedError("Completion is not implemented for %s" % R.__class__) F, BR = R.construction() M = self.merge(F) or F.merge(self) if M is not None: return M(BR) if self.commutes(F) or F.commutes(self): return F(self(BR)) - raise NotImplementedError("Don't know how to apply %s to %s"%(repr(self),repr(R))) + raise NotImplementedError("Don't know how to apply %s to %s" % (repr(self), repr(R))) def __eq__(self, other): """ @@ -2586,11 +2588,16 @@ def merge(self, other): from sage.all import Infinity if self.p == Infinity: new_prec = min(self.prec, other.prec) - new_type = self._real_types[min(self._real_types.index(self.type), \ + new_type = self._real_types[min(self._real_types.index(self.type), self._real_types.index(other.type))] - new_scinot = max(self.extras.get('sci_not',0), other.extras.get('sci_not',0)) - new_rnd = min(self.extras.get('rnd', 0), other.extras.get('rnd', 0)) - return CompletionFunctor(self.p, new_prec, {'type':new_type, 'sci_not':new_scinot, 'rnd':new_rnd}) + new_scinot = max(self.extras.get('sci_not', 0), + other.extras.get('sci_not', 0)) + new_rnd = min(self.extras.get('rnd', 0), + other.extras.get('rnd', 0)) + return CompletionFunctor(self.p, new_prec, + {'type': new_type, + 'sci_not': new_scinot, + 'rnd': new_rnd}) else: new_type = self._dvr_types[min(self._dvr_types.index(self.type), self._dvr_types.index(other.type))] if new_type in ('fixed-mod', 'floating-point'): @@ -2604,13 +2611,13 @@ def merge(self, other): extras['type'] = new_type return CompletionFunctor(self.p, new_prec, extras) -## Completion has a lower rank than FractionField -## and is thus applied first. However, fact is that -## both commute. This is used in the call method, -## since some fraction fields have no completion method -## implemented. +# Completion has a lower rank than FractionField +# and is thus applied first. However, fact is that +# both commute. This is used in the call method, +# since some fraction fields have no completion method +# implemented. - def commutes(self,other): + def commutes(self, other): """ Completion commutes with fraction fields. @@ -2755,12 +2762,12 @@ def _apply_functor(self, R): if I.ring().has_coerce_map_from(R): R = I.ring() else: - R = pushout(R,I.ring().base_ring()) - I = [R(1)*t for t in I.gens()]*R + R = pushout(R, I.ring().base_ring()) + I = [R.one() * t for t in I.gens()] * R try: - Q = R.quo(I,names=self.names) + Q = R.quo(I, names=self.names) except IndexError: # That may happen! - raise CoercionException("Can not apply this quotient functor to %s"%R) + raise CoercionException("Can not apply this quotient functor to %s" % R) if self.as_field:# and hasattr(Q, 'field'): try: Q = Q.field() @@ -3049,9 +3056,9 @@ def _apply_functor(self, R): """ from sage.all import QQ, ZZ, CyclotomicField if self.cyclotomic: - if R==QQ: + if R == QQ: return CyclotomicField(self.cyclotomic) - if R==ZZ: + if R == ZZ: return CyclotomicField(self.cyclotomic).maximal_order() if len(self.polys) == 1: return R.extension(self.polys[0], names=self.names[0], embedding=self.embeddings[0], @@ -3093,7 +3100,7 @@ def __ne__(self, other): __hash__ = ConstructionFunctor.__hash__ - def merge(self,other): + def merge(self, other): """ Merging with another :class:`AlgebraicExtensionFunctor`. @@ -3116,7 +3123,7 @@ def merge(self,other): - If these two extensions are defined by Conway polynomials over finite fields, merges them into a single extension of degree the lcm of the two degrees. - - Otherwise, None is returned. + - Otherwise, ``None`` is returned. REMARK: @@ -3187,12 +3194,12 @@ def merge(self,other): # *after* expanding the functors. Hence, we can # assume that both functors have a single variable. # But for being on the safe side...: - if len(self.names)!=1 or len(other.names)!=1: + if not (len(self.names) == 1 == len(other.names)): return None -## We don't accept a forgetful coercion, since, together -## with bidirectional coercions between two embedded -## number fields, it would yield to contradictions in -## the coercion system. +# We don't accept a forgetful coercion, since, together +# with bidirectional coercions between two embedded +# number fields, it would yield to contradictions in +# the coercion system. # if self.polys==other.polys and self.names==other.names: # # We have a forgetful functor: # if self.embeddings==[None]: @@ -3200,7 +3207,7 @@ def merge(self,other): # if other.embeddings==[None]: # return other # ... or we may use the given embeddings: - if self.embeddings!=[None] and other.embeddings!=[None]: + if self.embeddings != [None] and other.embeddings != [None]: from sage.all import QQ KS = self(QQ) KO = other(QQ) @@ -3219,10 +3226,11 @@ def merge(self,other): # Finite fields and unramified local extensions may use # integers to encode degrees of extensions. from sage.rings.integer import Integer - if (isinstance(self.polys[0], Integer) and isinstance(other.polys[0], Integer) - and self.embeddings == other.embeddings == [None] - and self.structures == other.structures == [None] - and self.kwds == other.kwds): + if (isinstance(self.polys[0], Integer) + and isinstance(other.polys[0], Integer) + and self.embeddings == other.embeddings == [None] + and self.structures == other.structures == [None] + and self.kwds == other.kwds): return AlgebraicExtensionFunctor([self.polys[0].lcm(other.polys[0])], [None], **self.kwds) def __mul__(self, other): @@ -3244,7 +3252,7 @@ def __mul__(self, other): True """ - if isinstance(other,IdentityConstructionFunctor): + if isinstance(other, IdentityConstructionFunctor): return self if isinstance(other, AlgebraicExtensionFunctor): if set(self.names).intersection(other.names): @@ -3255,8 +3263,8 @@ def __mul__(self, other): precs=self.precs + other.precs, implementations=self.implementations + other.implementations, **self.kwds) - elif isinstance(other, CompositeConstructionFunctor) \ - and isinstance(other.all[-1], AlgebraicExtensionFunctor): + elif (isinstance(other, CompositeConstructionFunctor) + and isinstance(other.all[-1], AlgebraicExtensionFunctor)): return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) else: return CompositeConstructionFunctor(other, self) @@ -3336,7 +3344,7 @@ def _apply_functor(self, R): """ try: c = R.construction() - if c is not None and c[0]==self: + if c is not None and c[0] == self: return R except AttributeError: pass @@ -3350,14 +3358,14 @@ def merge(self, other): TESTS:: - sage: K.=NumberField(x^3+x^2+1) + sage: K. = NumberField(x^3+x^2+1) sage: CDF.construction()[0].merge(K.construction()[0]) is None True sage: CDF.construction()[0].merge(CDF.construction()[0]) AlgebraicClosureFunctor """ - if self==other: + if self == other: return self return None # Mathematically, Algebraic Closure subsumes Algebraic Extension. @@ -3392,7 +3400,7 @@ def _repr_(self): sage: PF PermutationGroupFunctor[(1,2)] """ - return "PermutationGroupFunctor%s"%self.gens() + return "PermutationGroupFunctor%s" % self.gens() def __call__(self, R): """ @@ -3420,7 +3428,7 @@ def gens(self): def merge(self, other): """ - Merge ``self`` with another construction functor, or return None. + Merge ``self`` with another construction functor, or return ``None``. EXAMPLES:: @@ -3487,7 +3495,7 @@ def __init__(self, box): sage: FM == loads(dumps(FM)) True """ - ConstructionFunctor.__init__(self,Objects(),Objects()) + ConstructionFunctor.__init__(self, Objects(), Objects()) if not callable(box): raise TypeError("input must be callable") self.box = box @@ -3987,8 +3995,8 @@ def pushout(R, S): S_tower = expand_tower(S_tower[:len(Ss)]) else: # Rc is a list of functors from Z to R and Sc is a list of functors from Z to S - R_tower = expand_tower(R_tower[:len(Rs)+1]) - S_tower = expand_tower(S_tower[:len(Ss)+1]) + R_tower = expand_tower(R_tower[:len(Rs) + 1]) + S_tower = expand_tower(S_tower[:len(Ss) + 1]) Rc = [c[0] for c in R_tower[1:]] Sc = [c[0] for c in S_tower[1:]] @@ -4007,9 +4015,9 @@ def apply_from(Xc): try: while Rc or Sc: # if we are out of functors in either tower, there is no ambiguity - if len(Sc) == 0: + if not Sc: all = apply_from(Rc) - elif len(Rc) == 0: + elif not Rc: all = apply_from(Sc) # if one of the functors has lower rank, do it first elif Rc[-1].rank < Sc[-1].rank: @@ -4066,7 +4074,6 @@ def apply_from(Xc): raise CoercionException(ex) - def pushout_lattice(R, S): r""" Given a pair of objects `R` and `S`, try to construct a @@ -4117,11 +4124,11 @@ def pushout_lattice(R, S): return None # truncate at common ancestor - R_tower = list(reversed(R_tower[:Rs.index(start)+1])) - S_tower = list(reversed(S_tower[:Ss.index(start)+1])) - Rs = [c[1] for c in R_tower] # the list of objects + R_tower = list(reversed(R_tower[:Rs.index(start) + 1])) + S_tower = list(reversed(S_tower[:Ss.index(start) + 1])) + Rs = [c[1] for c in R_tower] # the list of objects Ss = [c[1] for c in S_tower] - Rc = [c[0] for c in R_tower] # the list of functors + Rc = [c[0] for c in R_tower] # the list of functors Sc = [c[0] for c in S_tower] # Here we try and construct a 2-dimensional lattice as follows. @@ -4135,10 +4142,10 @@ def pushout_lattice(R, S): # / \ # Qp Frac(Z[t]) # - for i in range(len(Rs)): - lattice[i,0] = Rs[i] - for j in range(len(Ss)): - lattice[0,j] = Ss[j] + for i, Rsi in enumerate(Rs): + lattice[i, 0] = Rsi + for j, Ssj in enumerate(Ss): + lattice[0, j] = Ssj # Now we attempt to fill in the center, one (diagonal) row at a time, # one commuting square at a time. @@ -4158,42 +4165,43 @@ def pushout_lattice(R, S): # Note that when applying the functors in the correct order, base extension # is not needed (though it may occur in the resulting morphisms). # - for i in range(len(Rc)-1): - for j in range(len(Sc)-1): + for i in range(len(Rc) - 1): + for j in range(len(Sc) - 1): try: - if lattice[i,j+1] == lattice[i+1,j]: + if lattice[i, j + 1] == lattice[i + 1, j]: # In this case we have R <- S -> R # We don't want to perform the operation twice # and all subsequent squares will come from objects # where the operation was already performed (either # to the left or right) Rc[i] = Sc[j] = None # IdentityConstructionFunctor() - lattice[i+1,j+1] = lattice[i,j+1] + lattice[i + 1, j + 1] = lattice[i, j + 1] elif Rc[i] is None and Sc[j] is None: - lattice[i+1,j+1] = lattice[i,j+1] + lattice[i + 1, j + 1] = lattice[i, j + 1] elif Rc[i] is None: - lattice[i+1,j+1] = Sc[j](lattice[i+1,j]) + lattice[i + 1, j + 1] = Sc[j](lattice[i + 1, j]) elif Sc[j] is None: - lattice[i+1,j+1] = Rc[i](lattice[i,j+1]) + lattice[i + 1, j + 1] = Rc[i](lattice[i, j + 1]) else: # For now, we just look at the rank. # TODO: be more sophisticated and query the functors themselves if Rc[i].rank < Sc[j].rank: - lattice[i+1,j+1] = Sc[j](lattice[i+1,j]) - Rc[i] = None # force us to use pre-applied Rc[i] + lattice[i + 1, j + 1] = Sc[j](lattice[i + 1, j]) + Rc[i] = None # force us to use pre-applied Rc[i] else: - lattice[i+1,j+1] = Rc[i](lattice[i,j+1]) - Sc[j] = None # force us to use pre-applied Sc[i] + lattice[i + 1, j + 1] = Rc[i](lattice[i, j + 1]) + Sc[j] = None # force us to use pre-applied Sc[i] except (AttributeError, NameError): # pp(lattice) - for i in range(100): - for j in range(100): + for ni in range(100): + for nj in range(100): try: - R = lattice[i,j] - print(i, j, R) + R = lattice[ni, nj] + print(ni, nj, R) except KeyError: break - raise CoercionException("%s does not support %s" % (lattice[i,j], 'F')) + raise CoercionException("%s does not support %s" + % (lattice[ni, nj], 'F')) # If we are successful, we should have something that looks like this. # @@ -4207,41 +4215,43 @@ def pushout_lattice(R, S): # \ / # Frac(Qp[t]) # - R_loc = len(Rs)-1 - S_loc = len(Ss)-1 + R_loc = len(Rs) - 1 + S_loc = len(Ss) - 1 # Find the composition coercion morphisms along the bottom left... if S_loc > 0: - R_map = lattice[R_loc,1].coerce_map_from(R) + R_map = lattice[R_loc, 1].coerce_map_from(R) for i in range(1, S_loc): - map = lattice[R_loc, i+1].coerce_map_from(lattice[R_loc, i]) # The functor used is implicit here, should it be? + map = lattice[R_loc, i + 1].coerce_map_from(lattice[R_loc, i]) + # The functor used is implicit here, should it be? R_map = map * R_map else: - R_map = R.coerce_map_from(R) # id + R_map = R.coerce_map_from(R) # id # ... and bottom right if R_loc > 0: S_map = lattice[1, S_loc].coerce_map_from(S) for i in range(1, R_loc): - map = lattice[i+1, S_loc].coerce_map_from(lattice[i, S_loc]) + map = lattice[i + 1, S_loc].coerce_map_from(lattice[i, S_loc]) S_map = map * S_map else: - S_map = S.coerce_map_from(S) # id + S_map = S.coerce_map_from(S) # id return R_map, S_map -## def pp(lattice): -## """ -## Used in debugging to print the current lattice. -## """ -## for i in range(100): -## for j in range(100): -## try: -## R = lattice[i,j] -## print(i, j, R) -## except KeyError: -## break +# def pp(lattice): +# """ +# Used in debugging to print the current lattice. +# """ +# for i in range(100): +# for j in range(100): +# try: +# R = lattice[i,j] +# print(i, j, R) +# except KeyError: +# break + def construction_tower(R): """ @@ -4271,12 +4281,13 @@ def construction_tower(R): f, R = c if not isinstance(f, ConstructionFunctor): f = BlackBoxConstructionFunctor(f) - tower.append((f,R)) + tower.append((f, R)) if not isinstance(R, Parent): break c = R.construction() return tower + def expand_tower(tower): """ An auxiliary function that is used in :func:`pushout`. @@ -4315,6 +4326,7 @@ def expand_tower(tower): new_tower.append((fs[0], R)) return list(reversed(new_tower)) + def type_to_parent(P): """ An auxiliary function that is used in :func:`pushout`. From 9a0bd59765680485099e4bb43cb501e40dd23383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 May 2020 20:09:04 +0200 Subject: [PATCH 180/476] fix some details in the doc of Zinbiel algebras --- src/sage/algebras/free_zinbiel_algebra.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index ce378ef1e0a..63cd7023e57 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -40,7 +40,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): .. MATH:: - a \circ (b \circ c) = a \circ (b \circ c) + a \circ (c \circ b). + (a \circ b) \circ c = a \circ (b \circ c) + a \circ (c \circ b). Zinbiel algebras were first introduced by Loday (see [Lod1995]_ and [LV2012]_) as the Koszul dual to Leibniz algebras (hence the name @@ -114,7 +114,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): sage: x*(y*z) + x*(z*y) Z[xyz] + Z[xzy] - We see that the Zinbiel algebra is not associative, nor even + We see that the Zinbiel algebra is not associative, not even power associative:: sage: x*(y*z) @@ -124,7 +124,7 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): sage: (x*x)*x 2*Z[xxx] - We verify that it is a divided powers algebra:: + We verify that it is a divided power algebra:: sage: (x*(x*x)) * (x*(x*(x*x))) 15*Z[xxxxxxx] @@ -479,7 +479,7 @@ def _coerce_map_from_(self, R): def construction(self): """ Return a pair ``(F, R)``, where ``F`` is a :class:`ZinbielFunctor` - and `R` is a ring, such that ``F(R)`` returns ``self``. + and ``R`` is a ring, such that ``F(R)`` returns ``self``. EXAMPLES:: @@ -654,7 +654,7 @@ def check(x): def merge(self, other): """ - Merge ``self`` with another construction functor, or return None. + Merge ``self`` with another construction functor, or return ``None``. EXAMPLES:: From 7051806db961bc5a27608badb101087dbe2dd30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 May 2020 20:27:19 +0200 Subject: [PATCH 181/476] trac 29682 fix unicode detail --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 573411d772e..9e15c67a938 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -234,7 +234,7 @@ def _repr_(self): def merge(self, other): """ - Merge ``self`` with another construction functor, or return ̀̀None``. + Merge ``self`` with another construction functor, or return ``None``. .. NOTE:: From 178d3b7a1c005b50c47b8ca8e7e6528c00add5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 May 2020 21:53:41 +0200 Subject: [PATCH 182/476] enhance conversion of dilog to sympy --- src/sage/functions/log.py | 41 ++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index 1f9ddcb0be2..08f9d9a2eb6 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -8,8 +8,6 @@ - Tomas Kalvoda (2015-04-01): Add :meth:`exp_polar()` (:trac:`18085`) """ -from six.moves import range - from sage.symbolic.function import GinacFunction, BuiltinFunction from sage.symbolic.constants import e as const_e from sage.symbolic.constants import pi as const_pi @@ -445,6 +443,7 @@ def log(*args, **kwds): except (AttributeError, TypeError): return logb(args[0], args[1]) + class Function_polylog(GinacFunction): def __init__(self): r""" @@ -538,14 +537,21 @@ def __init__(self): [1.644934066848226 +/- ...] sage: parent(_) Complex ball field with 53 bits of precision + + sage: polylog(1,-1) # known bug + -log(2) """ - GinacFunction.__init__(self, "polylog", nargs=2) + GinacFunction.__init__(self, "polylog", nargs=2, + conversions=dict(mathematica='PolyLog', + magma='Polylog', + matlab='polylog', + sympy='polylog')) def _maxima_init_evaled_(self, *args): """ EXAMPLES: - These are indirect doctests for this function.:: + These are indirect doctests for this function:: sage: polylog(2, x)._maxima_() li[2](_SAGE_VAR_x) @@ -562,14 +568,15 @@ def _maxima_init_evaled_(self, *args): args_maxima.append(str(a)) n, x = args_maxima - if int(n) in [1,2,3]: - return 'li[%s](%s)'%(n, x) + if int(n) in [1, 2, 3]: + return 'li[%s](%s)' % (n, x) else: - return 'polylog(%s, %s)'%(n, x) + return 'polylog(%s, %s)' % (n, x) polylog = Function_polylog() + class Function_dilog(GinacFunction): def __init__(self): r""" @@ -657,8 +664,27 @@ def __init__(self): """ GinacFunction.__init__(self, 'dilog', conversions=dict(maxima='li[2]', + magma='Dilog', fricas='(x+->dilog(1-x))')) + def _sympy_(self, z): + r""" + Special case for sympy, where there is no dilog function. + + EXAMPLES:: + + sage: w = dilog(x)._sympy_(); w + polylog(2, x) + sage: w.diff() + polylog(1, x)/x + sage: w._sage_() + dilog(x) + """ + import sympy + from sympy import polylog as sympy_polylog + return sympy_polylog(2, sympy.sympify(z, evaluate=False)) + + dilog = Function_dilog() @@ -1389,6 +1415,7 @@ def _swap_harmonic(a,b): return harmonic_number(b,a) register_symbol(_swap_harmonic,{'maxima':'gen_harmonic_number'}) register_symbol(_swap_harmonic,{'maple':'harmonic'}) + class Function_harmonic_number(BuiltinFunction): r""" Harmonic number function, defined by: From 256c9f83745ab9b084533d8da3c848d9c127aacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 May 2020 18:23:08 +0200 Subject: [PATCH 183/476] yet another little fix in shuffle algebras --- src/sage/algebras/shuffle_algebra.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index c9816cd1e27..86b8b8c1cac 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -115,6 +115,15 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: R = ShuffleAlgebra(QQ,'xy') sage: R.is_commutative() True + + Check for a fix when using numbers as generators:: + + sage: A = algebras.Shuffle(QQ,[0,1]) + sage: A_d = A.dual_pbw_basis() + sage: W = A.basis().keys() + sage: x = A(W([0,1,0])) + sage: A_d(x) + -2*S[word: 001] + S[word: 010] """ @staticmethod def __classcall_private__(cls, R, names, prefix=None): @@ -379,6 +388,12 @@ def algebra_generators(self): sage: A = ShuffleAlgebra(QQ, ['x1','x2']) sage: A.algebra_generators() Family (B[word: x1], B[word: x2]) + + TESTS:: + + sage: A = ShuffleAlgebra(ZZ,[0,1]) + sage: A.algebra_generators() + Family (B[word: 0], B[word: 1]) """ Words = self.basis().keys() return Family([self.monomial(Words([a])) for a in self._alphabet]) @@ -765,7 +780,7 @@ def algebra_generators(self): (S[word: a], S[word: b]) """ W = self.basis().keys() - return tuple(self.monomial(W(a)) for a in self._alphabet) + return tuple(self.monomial(W([a])) for a in self._alphabet) gens = algebra_generators @@ -941,7 +956,7 @@ def expansion_on_basis(self, w): return self._alg.monomial(w) if w.is_lyndon(): W = self.basis().keys() - letter = W(w[0]) + letter = W([w[0]]) expansion = self.expansion_on_basis(W(w[1:])) return self._alg.sum_of_terms((letter * i, c) for i, c in expansion) From 273b81652d5f894a4a7828eb690bf218d25af60f Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 12 May 2020 20:12:42 -0700 Subject: [PATCH 184/476] trac 29680: change message printed by "sage --package fix-checksum" --- build/sage_bootstrap/app.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index 45818546a18..30a4d90c917 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -137,10 +137,10 @@ def fix_all_checksums(self): log.debug('Ignoring {0} because tarball is not cached'.format(pkg.tarball_filename)) continue if pkg.tarball.checksum_verifies(): - log.debug('Checksum of {0} unchanged'.format(pkg.tarball_filename)) + log.debug('Checksum of {0} (tarball {1}) unchanged'.format(pkg.name, pkg.tarball_filename)) continue update = ChecksumUpdater(pkg.name) - print('Updating checksum of {0}'.format(pkg.tarball_filename)) + print('Updating checksum of {0} (tarball {1})'.format(pkg.name, pkg.tarball_filename)) update.fix_checksum() def fix_checksum(self, package_name): @@ -154,9 +154,9 @@ def fix_checksum(self, package_name): update = ChecksumUpdater(package_name) pkg = update.package if pkg.tarball.checksum_verifies(): - print('Checksum of {0} unchanged'.format(pkg.tarball_filename)) + print('Checksum of {0} (tarball {1}) unchanged'.format(package_name, pkg.tarball_filename)) else: - print('Updating checksum of {0}'.format(pkg.tarball_filename)) + print('Updating checksum of {0} (tarball {1})'.format(package_name, pkg.tarball_filename)) update.fix_checksum() def create(self, package_name, version, tarball, pkg_type, upstream_url): From 8dd8523a19f41c9711a5ad9201dfa57e0f256e02 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 14 May 2020 16:02:12 -0700 Subject: [PATCH 185/476] trac 29680: documentation and testing fixes --- build/sage_bootstrap/cmdline.py | 2 +- build/test/test_package_cmdline.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index abb617dd65a..48dc0d9c3fe 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -134,7 +134,7 @@ EXAMPLE: $ sage --package fix-checksum pari - Updating checksum of pari-2.8-2044-g89b0f1e.tar.gz + Updating checksum of pari (tarball pari-2.8-2044-g89b0f1e.tar.gz) """ epilog_create = \ diff --git a/build/test/test_package_cmdline.py b/build/test/test_package_cmdline.py index 69011314e1f..739fbe76d30 100644 --- a/build/test/test_package_cmdline.py +++ b/build/test/test_package_cmdline.py @@ -140,7 +140,7 @@ def test_fix_checksum(self): # Prints to stdout self.assertEqual( stdout.rstrip(), - 'Checksum of {0} unchanged'.format(pkg.tarball_filename)) + 'Checksum of {0} (tarball {1}) unchanged'.format(pkg.name, pkg.tarball_filename)) def test_create(self): tmp = tempfile.mkdtemp() From 506edd61bcaac326b5449577cbbdac2100d37665 Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Fri, 15 May 2020 17:04:14 -0600 Subject: [PATCH 186/476] fix bug in closure of braid --- src/sage/knots/link.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index eda927fb177..015c0dab4b9 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -312,6 +312,15 @@ def __init__(self, data): Traceback (most recent call last): ... ValueError: invalid input: data must be either a list or a braid + + Verify that :trac:`29692` is fixed:: + + sage: B = BraidGroup(5) + sage: L = Link(B([3,4,3,-4])) + sage: L + Link with 1 component represented by 4 crossings + sage: L.braid() + s0*s1*s0*s1^-1 """ if isinstance(data, list): if len(data) != 2 or not all(isinstance(i, list) for i in data[0]): @@ -340,20 +349,7 @@ def __init__(self, data): from sage.groups.braid import Braid, BraidGroup if isinstance(data, Braid): # Remove all unused strands - support = sorted(set(abs(x) for x in data.Tietze())) - i = 0 - cur = 1 - while i < len(support): - if support[i] == cur: - cur += 1 - i += 1 - elif support[i] == cur + 1: - support.insert(i, cur+1) - cur += 2 - i += 2 - else: - cur = support[i] - i += 1 + support = sorted(set().union(*((abs(x), abs(x) + 1) for x in data.Tietze()))) d = {} for i,s in enumerate(support): d[s] = i+1 @@ -361,7 +357,7 @@ def __init__(self, data): if not support: B = BraidGroup(2) else: - B = BraidGroup(len(support)+1) + B = BraidGroup(len(support)) self._braid = B([d[x] for x in data.Tietze()]) self._oriented_gauss_code = None self._pd_code = None From 9a57ddea1e8ed2966573d14b977cf920543fa147 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 11:00:35 +1000 Subject: [PATCH 187/476] Improve the iterator, monomial, and exponents of libsingular MPolys. --- .../multi_polynomial_libsingular.pyx | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ab1879650e4..626a23be8a4 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3126,6 +3126,39 @@ cdef class MPolynomial_libsingular(MPolynomial): p_Delete(&m,r) return self._parent._base._zero_element + def __iter__(self): + """ + Facilitates iterating over the monomials of self, + returning tuples of the form ``(coeff, mon)`` for each + non-zero monomial. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ, order='degrevlex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z + sage: list(f) + [(23, x^6*y^7), (6, x^7*z), (1, x^3*y)] + + sage: R. = PolynomialRing(QQ, order='lex') + sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z + sage: list(f) + [(6, x^7*z), (23, x^6*y^7), (1, x^3*y)] + """ + cdef MPolynomialRing_libsingular parent = self._parent + cdef ring *_ring = parent._ring + if _ring != currRing: rChangeCurrRing(_ring) + base = parent._base + cdef poly *p = p_Copy(self._poly, _ring) + + while p: + t = pNext(p) + p.next = NULL + coeff = si2sa(p_GetCoeff(p, _ring), _ring, base) + p_SetCoeff(p, n_Init(1,_ring), _ring) + p_Setm(p, _ring) + yield (coeff, new_MP(parent, p)) + p = t + def exponents(self, as_ETuples=True): """ Return the exponents of the monomials appearing in this @@ -3133,9 +3166,8 @@ cdef class MPolynomial_libsingular(MPolynomial): INPUT: - - ``as_ETuples`` - (default: ``True``) if true returns the result as an list of ETuples - otherwise returns a list of tuples - + - ``as_ETuples`` -- (default: ``True``) if ``True`` returns the + result as an list of ETuples, otherwise returns a list of tuples EXAMPLES:: @@ -3153,16 +3185,18 @@ cdef class MPolynomial_libsingular(MPolynomial): pl = list() ml = list(xrange(r.N)) - while p: - for v from 1 <= v <= r.N: - ml[v-1] = p_GetExp(p,v,r) - - if as_ETuples: + if as_ETuples: + while p: + for v from 1 <= v <= r.N: + ml[v-1] = p_GetExp(p,v,r) pl.append(ETuple(ml)) - else: + p = pNext(p) + else: + while p: + for v from 1 <= v <= r.N: + ml[v-1] = p_GetExp(p,v,r) pl.append(tuple(ml)) - - p = pNext(p) + p = pNext(p) return pl def inverse_of_unit(self): @@ -3609,16 +3643,13 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: p.monomials() [x] """ - l = list() + cdef list l = [] cdef MPolynomialRing_libsingular parent = self._parent cdef ring *_ring = parent._ring if(_ring != currRing): rChangeCurrRing(_ring) cdef poly *p = p_Copy(self._poly, _ring) cdef poly *t - if p == NULL: - return [] - while p: t = pNext(p) p.next = NULL From ede384712ab4fd6bd68d71a965591ed37531e2d3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 11:23:12 +1000 Subject: [PATCH 188/476] Improving generic MPoly iterator, monomials, and exponents. --- .../polynomial/multi_polynomial_element.py | 116 ++++++++++++------ 1 file changed, 80 insertions(+), 36 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index e5d692150c6..d8e4eec0541 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -66,6 +66,7 @@ from sage.structure.sequence import Sequence from .multi_polynomial import MPolynomial from sage.categories.morphism import Morphism +from sage.misc.lazy_attribute import lazy_attribute def is_MPolynomial(x): @@ -784,12 +785,12 @@ def dict(self): def __getitem__(self, x): """ - INPUT: - + Return the coefficient corresponding to ``x``. - - ``x`` - a tuple or, in case of a single-variable - MPolynomial ring x can also be an integer. + INPUT: + - ``x`` -- a tuple or, in case of a single-variable + MPolynomial ring x can also be an integer EXAMPLES:: @@ -823,6 +824,41 @@ def __getitem__(self, x): except KeyError: return self.parent().base_ring()(0) + def __iter__(self): + """ + Iterate over ``self`` respecting the term order. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQbar, order='lex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x^4*y*z^3), (1, x^2*z), (1, x*y^5*z^2)] + + :: + + sage: R. = PolynomialRing(QQbar, order='deglex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x^4*y*z^3), (1, x*y^5*z^2), (1, x^2*z)] + + :: + + sage: R. = PolynomialRing(QQbar, order='degrevlex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x*y^5*z^2), (1, x^4*y*z^3), (1, x^2*z)] + """ + elt = self.element() + ring = self.parent() + one = ring.base_ring()(1) + for exp in self._exponents: + yield (elt[exp], + MPolynomial_polydict(ring, polydict.PolyDict({exp:one}, + force_int_exponents=False, + force_etuples=False)) + ) + def coefficient(self, degrees): """ Return the coefficient of the variables with the degrees specified @@ -899,7 +935,7 @@ def coefficient(self, degrees): """ looking_for = None if isinstance(degrees, MPolynomial) and degrees.parent() == self.parent() and degrees.is_monomial(): - looking_for = [e if e > 0 else None for e in degrees.exponents()[0]] + looking_for = [e if e > 0 else None for e in degrees._exponents[0]] elif isinstance(degrees, list): looking_for = degrees elif isinstance(degrees, dict): @@ -913,18 +949,33 @@ def coefficient(self, degrees): raise ValueError("You must pass a dictionary list or monomial.") return self.parent()(self.element().polynomial_coefficient(looking_for)) - def exponents(self, as_ETuples=True): + @lazy_attribute + def _exponents(self): + """ + Return the exponents of the monomials appearing in ``self`` for + internal use only. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQbar, 3) + sage: f = a^3 + b + 2*b^2 + sage: f._exponents + [(3, 0, 0), (0, 2, 0), (0, 1, 0)] """ - Return the exponents of the monomials appearing in self. + return sorted(self.element().dict(), key=self.parent().term_order().sortkey, reverse=True) + + def exponents(self, as_ETuples=True): + r""" + Return the exponents of the monomials appearing in ``self``. INPUT: - - as_ETuples (default: ``True``): return the list of exponents as a list - of ETuples. + - ``as_ETuples`` -- (default: ``True``): return the list of + exponents as a list of ETuples OUTPUT: - Return the list of exponents as a list of ETuples or tuples. + The list of exponents as a list of ETuples or tuples. EXAMPLES:: @@ -939,24 +990,24 @@ def exponents(self, as_ETuples=True): sage: type(f.exponents(as_ETuples=False)[0]) <... 'tuple'> + + TESTS: + + Check that we can mutate the list and not change the result:: + + sage: R. = PolynomialRing(QQbar, 3) + sage: f = a^3 + b + 2*b^2 + sage: E = f.exponents(); E + [(3, 0, 0), (0, 2, 0), (0, 1, 0)] + sage: E.pop() + (0, 1, 0) + sage: E != f.exponents() + True """ - try: - exp = self.__exponents - if as_ETuples: - return exp - else: - return [tuple(e) for e in exp] - except AttributeError: - self.__exponents = list(self.element().dict()) - try: - self.__exponents.sort(key=self.parent().term_order().sortkey, - reverse=True) - except AttributeError: - pass - if as_ETuples: - return self.__exponents - else: - return [tuple(e) for e in self.__exponents] + if as_ETuples: + return list(self._exponents) # Make a shallow copy + else: + return [tuple(e) for e in self._exponents] def inverse_of_unit(self): """ @@ -1182,15 +1233,8 @@ def monomials(self): """ ring = self.parent() one = ring.base_ring()(1) - return [MPolynomial_polydict(ring, polydict.PolyDict({m:one}, force_int_exponents=False, force_etuples=False)) for m in self.exponents()] - try: - return self.__monomials - except AttributeError: - ring = self.parent() - one = self.parent().base_ring()(1) - self.__monomials = sorted([ MPolynomial_polydict(ring, polydict.PolyDict( {m:one}, force_int_exponents=False, force_etuples=False ) ) \ - for m in self._MPolynomial_element__element.dict().keys() ], reverse=True) - return self.__monomials + return [MPolynomial_polydict(ring, polydict.PolyDict({m:one}, force_int_exponents=False, force_etuples=False)) + for m in self._exponents] def constant_coefficient(self): """ From 9c6e84a4cd7872590025c7c9578e3be7b9d4997f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 11:53:20 +1000 Subject: [PATCH 189/476] Improving some is_* methods of generic MPolys. --- .../polynomial/multi_polynomial_element.py | 44 +++++++------------ src/sage/rings/polynomial/polydict.pyx | 20 +++++++++ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index d8e4eec0541..96a4b7559ac 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -1020,12 +1020,11 @@ def inverse_of_unit(self): sage: l.inverse_of_unit().parent() Univariate Polynomial Ring in c over Rational Field """ - d = self.element().dict() - k = list(d) if self.is_unit(): - if len(k) != 1: + d = self.element().dict() + if len(d) != 1: raise NotImplementedError - return d[k[0]].inverse_of_unit() + return list(d.values())[0].inverse_of_unit() raise ArithmeticError("is not a unit") def is_homogeneous(self): @@ -1084,7 +1083,7 @@ def _homogenize(self, var): def is_generator(self): """ - Returns True if self is a generator of it's parent. + Return ``True`` if ``self`` is a generator of its parent. EXAMPLES:: @@ -1096,19 +1095,18 @@ def is_generator(self): sage: (x*y).is_generator() False """ - d = self.element().dict() - if len(d) == 1: - (e, c), = d.items() - if c.is_one() and len(e.nonzero_positions()) == 1 and e.nonzero_values()[0] == 1: - return True + elt = self.element() + if len(elt) == 1: + (e, c), = elt.dict().items() + return e.nonzero_values() == [1] and c.is_one() return False def is_monomial(self): """ - Returns True if self is a monomial, which we define to be a + Return ``True`` if ``self`` is a monomial, which we define to be a product of generators with coefficient 1. - Use is_term to allow the coefficient to not be 1. + Use :meth:`is_term` to allow the coefficient to not be 1. EXAMPLES:: @@ -1129,18 +1127,11 @@ def is_monomial(self): sage: (2*x*y).is_monomial() False """ - term = (len(self.element().dict().keys()) == 1) - if term: - if self.coefficients()[0] == 1: - return True - else: - return False - else: - return False + return len(self.element()) == 1 and self.element().coefficients()[0] == 1 def is_term(self): """ - Returns True if self is a term, which we define to be a + Return ``True`` if ``self`` is a term, which we define to be a product of generators times some coefficient, which need not be 1. @@ -1165,7 +1156,7 @@ def is_term(self): sage: (2*x*y).is_term() True """ - return len(self.element().dict().keys()) == 1 + return len(self.element()) == 1 def subs(self, fixed=None, **kw): """ @@ -1276,7 +1267,7 @@ def is_univariate(self): sage: f.is_univariate() True """ - mons = self.element().dict().keys() + mons = self.element().dict() found = -1 for mon in mons: @@ -1424,7 +1415,7 @@ def nvariables(self): def is_constant(self): """ - True if polynomial is constant, and False otherwise. + Return ``True`` if ``self`` is a constant and ``False`` otherwise. EXAMPLES:: @@ -1436,10 +1427,7 @@ def is_constant(self): sage: g.is_constant() True """ - if len(self.dict()) <= 1 and self.degrees().is_constant(): - return True - else: - return False + return self.element().is_constant() def lm(self): """ diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index f86c7c79905..48567384b9e 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -493,6 +493,26 @@ cdef class PolyDict: # exponent sums is at most 1. return len(set(map(sum, self.__repn))) <= 1 + def is_constant(self): + """ + Return ``True`` if ``self`` is a constant and ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.rings.polynomial.polydict import PolyDict + sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) + sage: f.is_constant() + False + sage: g = PolyDict({(0,0):2}) + sage: g.is_constant() + True + sage: h = PolyDict({}) + sage: h.is_constant() + True + """ + cdef int ell = len(self.__repn) + return ell == 0 or (ell == 1 and sum(sum(k) for k in self.__repn) == 0) + def homogenize(PolyDict self, var): R = self.__repn H = {} From 56312bea9a2122b3d607cfcd75ae32f764252823 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 12:17:16 +1000 Subject: [PATCH 190/476] Implementing an iterator_exp_coeff method for MPolys as a helper method. --- .../rings/polynomial/multi_polynomial.pyx | 35 ++++++++++--- .../polynomial/multi_polynomial_element.py | 29 +++++++++++ .../multi_polynomial_libsingular.pyx | 49 ++++++++++++++++++- 3 files changed, 104 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 7000594fdf1..5005386cf4e 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -1155,11 +1155,6 @@ cdef class MPolynomial(CommutativeRingElement): returning tuples of the form ``(coeff, mon)`` for each non-zero monomial. - .. NOTE:: - - This function creates the entire list upfront because Cython - doesn't (yet) support iterators. - EXAMPLES:: sage: P. = PolynomialRing(QQ,3) @@ -1170,8 +1165,34 @@ cdef class MPolynomial(CommutativeRingElement): sage: sum(c*m for c,m in f) == f True """ - L = zip(self.coefficients(), self.monomials()) - return iter(L) + for exp, coeff in self.iterator_exp_coeff(): + yield (coeff, self.monomial(exp)) + + def iterator_exp_coeff(self, as_ETuples=True): + """ + Iterate over ``self`` as pairs of ((E)Tuple, coefficient). + + INPUT: + + - ``as_ETuples`` -- (default: ``True``) if ``True`` iterate over + pairs whose first element is an ETuple, otherwise as a tuples + + EXAMPLES:: + + sage: R. = QQ[] + sage: f = a*c^3 + a^2*b + 2*b^4 + sage: list(f.iterator_exp_coeff()) + [((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)] + sage: list(f.iterator_exp_coeff(as_ETuples=False)) + [((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)] + + sage: R. = PolynomialRing(QQ, 3, order='lex') + sage: f = a*c^3 + a^2*b + 2*b^4 + sage: list(f.iterator_exp_coeff()) + [((2, 1, 0), 1), ((1, 0, 3), 1), ((0, 4, 0), 2)] + """ + for exp in self.exponents(): + yield (exp, self.monomial_coefficient(exp)) def content(self): """ diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 96a4b7559ac..ea51eebf0e1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -859,6 +859,35 @@ def __iter__(self): force_etuples=False)) ) + def iterator_exp_coeff(self, as_ETuples=True): + """ + Iterate over ``self`` as pairs of ((E)Tuple, coefficient). + + INPUT: + + - ``as_ETuples`` -- (default: ``True``) if ``True`` iterate over + pairs whose first element is an ETuple, otherwise as a tuples + + EXAMPLES:: + + sage: R. = PolynomialRing(QQbar, order='lex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f.iterator_exp_coeff()) + [((4, 1, 3), 1), ((2, 0, 1), 1), ((1, 5, 2), 1)] + + sage: R. = PolynomialRing(QQbar, order='deglex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f.iterator_exp_coeff(as_ETuples=False)) + [((4, 1, 3), 1), ((1, 5, 2), 1), ((2, 0, 1), 1)] + """ + elt = self.element() + if as_ETuples: + for exp in self._exponents: + yield (exp, elt[exp]) + else: + for exp in self._exponents: + yield (tuple(exp), elt[exp]) + def coefficient(self, degrees): """ Return the coefficient of the variables with the degrees specified diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 626a23be8a4..7b61b0f4d79 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2989,12 +2989,12 @@ cdef class MPolynomial_libsingular(MPolynomial): if r!=currRing: rChangeCurrRing(r) base = self._parent._base p = self._poly - pd = dict() + cdef dict d, pd = dict() while p: d = dict() for v from 1 <= v <= r.N: n = p_GetExp(p,v,r) - if n!=0: + if n != 0: d[v-1] = n pd[ETuple(d,r.N)] = si2sa(p_GetCoeff(p, r), r, base) @@ -3002,6 +3002,51 @@ cdef class MPolynomial_libsingular(MPolynomial): p = pNext(p) return pd + def iterator_exp_coeff(self, as_ETuples=True): + """ + Iterate over ``self`` as pairs of ((E)Tuple, coefficient). + + INPUT: + + - ``as_ETuples`` -- (default: ``True``) if ``True`` iterate over + pairs whose first element is an ETuple, otherwise as a tuples + + EXAMPLES:: + + sage: R. = QQ[] + sage: f = a*c^3 + a^2*b + 2*b^4 + sage: list(f.iterator_exp_coeff()) + [((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)] + sage: list(f.iterator_exp_coeff(as_ETuples=False)) + [((0, 4, 0), 2), ((1, 0, 3), 1), ((2, 1, 0), 1)] + + sage: R. = PolynomialRing(QQ, 3, order='lex') + sage: f = a*c^3 + a^2*b + 2*b^4 + sage: list(f.iterator_exp_coeff()) + [((2, 1, 0), 1), ((1, 0, 3), 1), ((0, 4, 0), 2)] + """ + cdef poly *p + cdef ring *r = self._parent_ring + cdef int n + cdef int v + if r!=currRing: rChangeCurrRing(r) + base = self._parent._base + p = self._poly + cdef dict d + while p: + d = dict() + for v from 1 <= v <= r.N: + n = p_GetExp(p,v,r) + if n != 0: + d[v-1] = n + + exp = ETuple(d,r.N) + if as_ETuples: + yield (exp, si2sa(p_GetCoeff(p, r), r, base)) + else: + yield (tuple(exp), si2sa(p_GetCoeff(p, r), r, base)) + p = pNext(p) + cpdef long number_of_terms(self): """ Return the number of non-zero coefficients of this polynomial. From a245839c427727192b073b4b1859137ef6778e93 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 14:03:00 +1000 Subject: [PATCH 191/476] Using old-style loop syntax to get good C code (and hence speed). --- src/sage/rings/polynomial/polydict.pyx | 32 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index 48567384b9e..57e6f719379 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -1268,7 +1268,9 @@ cdef class ETuple: d = [self[ind] for ind from start <= ind < stop] return ETuple(d) else: - for ind in range(0, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for ind in range(0, 2*self._nonzero, 2): + for ind from 0 <= ind < 2*self._nonzero by 2: if self._data[ind] == i: return self._data[ind+1] elif self._data[ind] > i: @@ -1281,7 +1283,9 @@ cdef class ETuple: Return the exponent for the ``i``-th variable. """ cdef size_t ind = 0 - for ind in range(0, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for ind in range(0, 2*self._nonzero, 2): + for ind from 0 <= ind < 2*self._nonzero by 2: if self._data[ind] == i: return self._data[ind+1] elif self._data[ind] > i: @@ -1502,7 +1506,9 @@ cdef class ETuple: """ cdef size_t degree = 0 cdef size_t i - for i in range(1, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for i in range(1, 2*self._nonzero, 2): + for i from 1 <= i < 2*self._nonzero by 2: degree += self._data[i] return degree @@ -1524,7 +1530,9 @@ cdef class ETuple: cdef size_t i cdef size_t deg = 0 assert len(w) == self._length - for i in range(0, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for i in range(0, 2*self._nonzero, 2): + for i from 0 <= i < 2*self._nonzero by 2: deg += self._data[i+1] * w[self._data[i]] return deg @@ -2001,17 +2009,23 @@ cdef class ETuple: if exp1>1: # division doesn't change the number of nonzero positions result._nonzero = self._nonzero - for j in range(0, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for j in range(0, 2*self._nonzero, 2): + for j from 0 <= j < 2*self._nonzero by 2: result._data[j] = self._data[j] result._data[j+1] = self._data[j+1] result._data[i+1] = exp1-1 else: # var(index) disappears from self result._nonzero = self._nonzero-1 - for j in range(0, i, 2): + # Do NOT change this as it will not produce an efficient for loop + #for ind in range(0, i, 2): + for j from 0 <= j < i by 2: result._data[j] = self._data[j] result._data[j+1] = self._data[j+1] - for j in range(i+2, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for j in range(i+2, 2*self._nonzero, 2): + for j from i+2 <= j < 2*self._nonzero by 2: result._data[j-2] = self._data[j] result._data[j-1] = self._data[j+1] return result @@ -2029,7 +2043,9 @@ cdef class ETuple: # Trivially self cannot divide other return False cdef size_t othernz2 = 2 * other._nonzero - for ind1 in range(0, 2*self._nonzero, 2): + # Do NOT change this as it will not produce an efficient for loop + #for ind1 in range(0, 2*self._nonzero, 2): + for ind1 from 0 <= ind1 < 2*self._nonzero by 2: pos1 = self._data[ind1] exp1 = self._data[ind1+1] # Because of the above trivial test, other._nonzero>0. From e85d0f4ab98d0afb0e528a7a5c54985319ade0b4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 14:06:20 +1000 Subject: [PATCH 192/476] Adding is_term and fixing bug with is_monomial of MPoly libsingular. --- .../multi_polynomial_libsingular.pyx | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 7b61b0f4d79..fff23e091ad 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3351,6 +3351,10 @@ cdef class MPolynomial_libsingular(MPolynomial): True sage: (x*y + x).is_monomial() False + sage: P(2).is_monomial() + False + sage: P.zero().is_monomial() + False """ cdef poly *_p cdef ring *_ring @@ -3358,7 +3362,7 @@ cdef class MPolynomial_libsingular(MPolynomial): _ring = self._parent_ring if self._poly == NULL: - return True + return False if(_ring != currRing): rChangeCurrRing(_ring) @@ -3370,6 +3374,32 @@ cdef class MPolynomial_libsingular(MPolynomial): p_Delete(&_p, _ring) return ret + def is_term(self): + """ + Return ``True`` if ``self`` is a term, which we define to be a + product of generators times some coefficient, which need + not be 1. + + Use :meth:`is_monomial()` to require that the coefficient be 1. + + EXAMPLES:: + + sage: P. = PolynomialRing(QQ) + sage: x.is_term() + True + sage: (2*x).is_term() + True + sage: (x*y).is_term() + True + sage: (x*y + x).is_term() + False + sage: P(2).is_term() + True + sage: P.zero().is_term() + True + """ + return self._poly == NULL or self._poly.next == NULL + def subs(self, fixed=None, **kw): """ Fixes some given variables in a given multivariate polynomial From 6e40f5ce6e560a2db785c2961baa6f1da0ce966e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 14:13:05 +1000 Subject: [PATCH 193/476] Improving Laurent MPolys and the 0 polynomial is not a term. --- .../rings/polynomial/laurent_polynomial.pyx | 109 ++++++++++-------- .../multi_polynomial_libsingular.pyx | 4 +- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 17904ad8b17..01b16cd627d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2045,7 +2045,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): cdef int p cdef int n = len(var_name_hash) cdef long c_hash - for m,c in self._poly.dict().iteritems(): + for m, c in self._poly.iterator_exp_coeff(): c_hash = hash(c) if c_hash != 0: for p in range(n): @@ -2117,10 +2117,12 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): self._mon = ETuple({}, int(self._parent.ngens())) return - cdef dict D = self._poly._mpoly_dict_recursive( - self._parent.variable_names(), - self._parent.base_ring() - ) + #cdef dict D = self._poly._mpoly_dict_recursive( + # self._parent.variable_names(), + # self._parent.base_ring() + # ) + cdef dict D = self._poly.dict() + cdef ETuple e if i is None: e = None @@ -2150,8 +2152,9 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: a.dict() # indirect doctest {(0, 0): 3, (2, -1): 1} """ - cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), - self._parent.base_ring()) + #cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), + # self._parent.base_ring()) + cdef dict D = self._poly.dict() cdef dict DD if self._mon.is_constant(): self._prod = PolyDict(D, force_etuples=False) @@ -2369,9 +2372,10 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): cdef ETuple t = ETuple(n) if self._prod is None: self._compute_polydict() - if t not in self._prod.exponents(): + try: + return self._prod[t] + except KeyError: return self._parent.base_ring().zero() - return self._prod[t] def __iter__(self): """ @@ -2385,17 +2389,28 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: sorted(f) # indirect doctest [(-7, x^-2*y^3), (-1, x^6), (1, x^-3*y^2), (5, x^-2*y)] """ - if self._prod is None: - self._compute_polydict() - cdef tuple G = self._parent.gens() - cdef Py_ssize_t i - cdef list exps - for c, e in self._prod.list(): - exps = e - prod = self._parent.one() - for i in range(len(exps)): - prod *= G[i]**exps[i] - yield (c, prod) + P = self._parent + one = P._R.one() + if self._mon.is_constant(): + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp)) + else: + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp.eadd(self._mon))) + + def iterator_exp_coeff(self): + """ + Iterate over ``self`` as pairs of (ETuple, coefficient). + + EXAMPLES:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: list(f.iterator_exp_coeff()) + [((6, 0), -1), ((-2, 3), -7), ((-2, 1), 5), ((-3, 2), 1)] + """ + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (exp.eadd(self._mon), coeff) def monomials(self): """ @@ -2408,18 +2423,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: sorted(f.monomials()) [x^-3*y^2, x^-2*y, x^-2*y^3, x^6] """ - cdef list L = [] - if self._prod is None: - self._compute_polydict() - cdef tuple gens = self._parent.gens() - cdef list exps - for c, e in self._prod.list(): - exps = e - prod = self._parent.one() - for i in range(len(exps)): - prod *= gens[i]**exps[i] - L.append(prod) - return L + return [mon for coeff, mon in self] def monomial_coefficient(self, mon): """ @@ -2448,18 +2452,29 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): -7 sage: f.monomial_coefficient(x^2) 0 + + TESTS:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: f = y^2 * x^-2 + sage: f.monomial_coefficient(x + y) + Traceback (most recent call last): + ... + ValueError: input must be a monomial """ if mon.parent() != self._parent: raise TypeError("input must have the same parent") cdef LaurentPolynomial_mpair m = mon - if self._prod is None: - self._compute_polydict() if m._prod is None: m._compute_polydict() + if len(m._prod) != 1: + raise ValueError("input must be a monomial") + if self._prod is None: + self._compute_polydict() c = self._prod.monomial_coefficient(m._prod.dict()) return self._parent.base_ring()(c) - def constant_coefficient(self): + def constant_coefficient(self, method=True): """ Return the constant coefficient of ``self``. @@ -2598,6 +2613,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): cpdef dict dict(self): """ + Return ``self`` represented as a ``dict``. + EXAMPLES:: sage: L. = LaurentPolynomialRing(QQ) @@ -2626,15 +2643,15 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) """ ring = self._parent._R - numer = self._poly - denom = ring.one() - var = ring.gens() + n = ring.ngens() + numer = [0] * n # monomial we multiply the numerator by + denom = [0] * n for i, j in enumerate(self._mon): if j > 0: - numer *= var[i] ** j + numer[i] = j else: - denom *= var[i] ** (-j) - return (numer, denom) + denom[i] = -j + return (self._poly * ring.monomial(*numer), ring.monomial(*denom)) cpdef _add_(self, _right): """ @@ -2713,8 +2730,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): cdef LaurentPolynomial_mpair right = rhs if right.is_zero(): raise ZeroDivisionError - cdef dict d = right.dict() - if len(d) == 1: + if right._poly.is_term(): return self * ~right else: return RingElement._div_(self, rhs) @@ -2737,9 +2753,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: (38*z^-2909).is_monomial() False """ - - d = self._poly.dict() - return len(d) == 1 and 1 in d.values() + return self._poly.is_monomial() cpdef _neg_(self): """ @@ -2905,7 +2919,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): ( right)._compute_polydict() try: - sortkey = self.parent().term_order().sortkey + sortkey = self._parent.term_order().sortkey except AttributeError: sortkey = None @@ -3418,3 +3432,4 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): ans._mon = mon ans._poly = root return (True, ans) + diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index fff23e091ad..83e6f4567ae 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3396,9 +3396,9 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: P(2).is_term() True sage: P.zero().is_term() - True + False """ - return self._poly == NULL or self._poly.next == NULL + return self._poly != NULL and self._poly.next == NULL def subs(self, fixed=None, **kw): """ From 08a2b7100ef8838ecc6c5681fdd154faf721f6c8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 15:26:41 +1000 Subject: [PATCH 194/476] Doing some cleanup and some reverts from timing and looking at the C code. --- .../rings/polynomial/laurent_polynomial.pyx | 21 ++++++------ src/sage/rings/polynomial/polydict.pyx | 32 +++++-------------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 01b16cd627d..c9af44acde8 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2286,12 +2286,11 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: parent(g.coefficients()[0]) is parent(g).base_ring() True """ - cdef dict d = self.dict() cdef ETuple e - if len(d) == 1: - (e, c), = d.items() + if self._poly.is_term(): + (e, c), = self.dict().items() e = e.emul(-1) - P = self.parent() + P = self._parent try: c = c.inverse_of_unit() except (AttributeError, ZeroDivisionError, ArithmeticError): @@ -2474,7 +2473,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): c = self._prod.monomial_coefficient(m._prod.dict()) return self._parent.base_ring()(c) - def constant_coefficient(self, method=True): + def constant_coefficient(self): """ Return the constant coefficient of ``self``. @@ -2643,15 +2642,15 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) """ ring = self._parent._R - n = ring.ngens() - numer = [0] * n # monomial we multiply the numerator by - denom = [0] * n + numer = self._poly + denom = ring.one() + var = ring.gens() for i, j in enumerate(self._mon): if j > 0: - numer[i] = j + numer *= var[i] ** j else: - denom[i] = -j - return (self._poly * ring.monomial(*numer), ring.monomial(*denom)) + denom *= var[i] ** (-j) + return (numer, denom) cpdef _add_(self, _right): """ diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index 57e6f719379..48567384b9e 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -1268,9 +1268,7 @@ cdef class ETuple: d = [self[ind] for ind from start <= ind < stop] return ETuple(d) else: - # Do NOT change this as it will not produce an efficient for loop - #for ind in range(0, 2*self._nonzero, 2): - for ind from 0 <= ind < 2*self._nonzero by 2: + for ind in range(0, 2*self._nonzero, 2): if self._data[ind] == i: return self._data[ind+1] elif self._data[ind] > i: @@ -1283,9 +1281,7 @@ cdef class ETuple: Return the exponent for the ``i``-th variable. """ cdef size_t ind = 0 - # Do NOT change this as it will not produce an efficient for loop - #for ind in range(0, 2*self._nonzero, 2): - for ind from 0 <= ind < 2*self._nonzero by 2: + for ind in range(0, 2*self._nonzero, 2): if self._data[ind] == i: return self._data[ind+1] elif self._data[ind] > i: @@ -1506,9 +1502,7 @@ cdef class ETuple: """ cdef size_t degree = 0 cdef size_t i - # Do NOT change this as it will not produce an efficient for loop - #for i in range(1, 2*self._nonzero, 2): - for i from 1 <= i < 2*self._nonzero by 2: + for i in range(1, 2*self._nonzero, 2): degree += self._data[i] return degree @@ -1530,9 +1524,7 @@ cdef class ETuple: cdef size_t i cdef size_t deg = 0 assert len(w) == self._length - # Do NOT change this as it will not produce an efficient for loop - #for i in range(0, 2*self._nonzero, 2): - for i from 0 <= i < 2*self._nonzero by 2: + for i in range(0, 2*self._nonzero, 2): deg += self._data[i+1] * w[self._data[i]] return deg @@ -2009,23 +2001,17 @@ cdef class ETuple: if exp1>1: # division doesn't change the number of nonzero positions result._nonzero = self._nonzero - # Do NOT change this as it will not produce an efficient for loop - #for j in range(0, 2*self._nonzero, 2): - for j from 0 <= j < 2*self._nonzero by 2: + for j in range(0, 2*self._nonzero, 2): result._data[j] = self._data[j] result._data[j+1] = self._data[j+1] result._data[i+1] = exp1-1 else: # var(index) disappears from self result._nonzero = self._nonzero-1 - # Do NOT change this as it will not produce an efficient for loop - #for ind in range(0, i, 2): - for j from 0 <= j < i by 2: + for j in range(0, i, 2): result._data[j] = self._data[j] result._data[j+1] = self._data[j+1] - # Do NOT change this as it will not produce an efficient for loop - #for j in range(i+2, 2*self._nonzero, 2): - for j from i+2 <= j < 2*self._nonzero by 2: + for j in range(i+2, 2*self._nonzero, 2): result._data[j-2] = self._data[j] result._data[j-1] = self._data[j+1] return result @@ -2043,9 +2029,7 @@ cdef class ETuple: # Trivially self cannot divide other return False cdef size_t othernz2 = 2 * other._nonzero - # Do NOT change this as it will not produce an efficient for loop - #for ind1 in range(0, 2*self._nonzero, 2): - for ind1 from 0 <= ind1 < 2*self._nonzero by 2: + for ind1 in range(0, 2*self._nonzero, 2): pos1 = self._data[ind1] exp1 = self._data[ind1+1] # Because of the above trivial test, other._nonzero>0. From df935f01c72aed5e027bfa9c1d27e1f6fde18cb2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 15:39:04 +1000 Subject: [PATCH 195/476] Declaring one more variable type. --- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 83e6f4567ae..63b4154362e 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3183,6 +3183,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z sage: list(f) [(23, x^6*y^7), (6, x^7*z), (1, x^3*y)] + sage: list(R.zero()) sage: R. = PolynomialRing(QQ, order='lex') sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z @@ -3193,7 +3194,7 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef ring *_ring = parent._ring if _ring != currRing: rChangeCurrRing(_ring) base = parent._base - cdef poly *p = p_Copy(self._poly, _ring) + cdef poly *t, *p = p_Copy(self._poly, _ring) while p: t = pNext(p) From 1f8587cf688d6cc2de9be506dd7ddad78801fd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 16 May 2020 09:27:16 +0200 Subject: [PATCH 196/476] fix handling of dead ticket in testing-code function --- src/sage/databases/oeis.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 77cdce92fa9..38441791bfe 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -1990,14 +1990,25 @@ def test_compile_sage_code(self): This returns ``True`` if the code compiles, and raises an error otherwise. - EXAMPLES:: + EXAMPLES: + + One correct sequence:: + + sage: s = oeis.find_by_id('A027642') # optional -- internet + sage: s.test_compile_sage_code() # optional -- internet + True + + One dead sequence:: - sage: s = oeis.find_by_id('A27642') # optional -- internet + sage: s = oeis.find_by_id('A000154') # optional -- internet sage: s.test_compile_sage_code() # optional -- internet + doctest:warning + ... + RuntimeWarning: This sequence is dead: ... True """ if self.is_dead(): - raise True + return True filt = self.programs(language='sage') if filt: for v in filt: From 4c8424ee3759d00e548d341b775dce40b919091d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 16 May 2020 17:30:28 +1000 Subject: [PATCH 197/476] Fixing a doctest. --- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 63b4154362e..1bae398726d 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -3184,6 +3184,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: list(f) [(23, x^6*y^7), (6, x^7*z), (1, x^3*y)] sage: list(R.zero()) + [] sage: R. = PolynomialRing(QQ, order='lex') sage: f = 23*x^6*y^7 + x^3*y+6*x^7*z From a62f873141e24293bf2b87933f7d761eadddac29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 16 May 2020 10:39:55 +0200 Subject: [PATCH 198/476] some doc details in oeis.py --- src/sage/databases/oeis.py | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 38441791bfe..bbbe5a32a35 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -105,7 +105,7 @@ ... -What does the Taylor expansion of the `e^(e^x-1)`` function have to do with +What does the Taylor expansion of the `e^(e^x-1)` function have to do with primes ? :: @@ -186,7 +186,7 @@ def _fetch(url): INPUT: - - ``url`` - a string corresponding to the URL to be fetched. + - ``url`` -- a string corresponding to the URL to be fetched. OUTPUT: @@ -217,7 +217,7 @@ def _urls(html_string): INPUT: - - ``html_string`` - a string representing some HTML code. + - ``html_string`` -- a string representing some HTML code. OUTPUT: @@ -402,10 +402,10 @@ def find_by_id(self, ident, fetch=False): INPUT: - - ``ident`` - a string representing the A-number of the sequence + - ``ident`` -- a string representing the A-number of the sequence or an integer representing its number. - - ``fetch`` - (bool, default: ``False``) whether to force fetching the + - ``fetch`` -- (bool, default: ``False``) whether to force fetching the content of the sequence on the internet. OUTPUT: @@ -430,7 +430,7 @@ def find_by_entry(self, entry): INPUT: - - ``entry`` - a string corresponding to an entry in the internal format + - ``entry`` -- a string corresponding to an entry in the internal format of the OEIS. OUTPUT: @@ -455,13 +455,13 @@ def find_by_description(self, description, max_results=3, first_result=0): INPUT: - - ``description`` - (string) the description the searched sequences. + - ``description`` -- (string) the description the searched sequences. - - ``max_results`` - (integer, default: 3) the maximum number of results + - ``max_results`` -- (integer, default: 3) the maximum number of results we want. In any case, the on-line encyclopedia will not return more than 100 results. - - ``first_result`` - (integer, default: 0) allow to skip the + - ``first_result`` -- (integer, default: 0) allow to skip the ``first_result`` first results in the search, to go further. This is useful if you are looking for a sequence that may appear after the 100 first found sequences. @@ -509,11 +509,11 @@ def find_by_subsequence(self, subsequence, max_results=3, first_result=0): INPUT: - - ``subsequence`` - a list of integers. + - ``subsequence`` -- a list of integers. - - ``max_results`` - (integer, default: 3), the maximum of results requested. + - ``max_results`` -- (integer, default: 3), the maximum of results requested. - - ``first_result`` - (integer, default: 0) allow to skip the + - ``first_result`` -- (integer, default: 0) allow to skip the ``first_result`` first results in the search, to go further. This is useful if you are looking for a sequence that may appear after the 100 first found sequences. @@ -554,9 +554,9 @@ def _imaginary_entry(self, ident='A999999', keywords=''): INPUT: - - ``ident`` - a string representing the A-number of the sequence. + - ``ident`` -- a string representing the A-number of the sequence. - - ``keywords`` - a string corresponding to the keyword field of the + - ``keywords`` -- a string corresponding to the keyword field of the sequence. OUTPUT: @@ -614,9 +614,9 @@ def _imaginary_sequence(self, ident='A999999', keywords='sign,easy'): INPUT: - - ``ident`` - a string representing the A-number of the sequence. + - ``ident`` -- a string representing the A-number of the sequence. - - ``keywords`` - string (default: 'sign,easy'), a list of words + - ``keywords`` -- string (default: 'sign,easy'), a list of words separated by commas. OUTPUT: @@ -692,7 +692,7 @@ def __init__(self, ident): INPUT: - - ``ident`` - a string representing the A-number of the sequence or an + - ``ident`` -- a string representing the A-number of the sequence or an integer representing its number. TESTS:: @@ -753,7 +753,7 @@ def id(self, format='A'): INPUT: - - ``format`` - (string, default: 'A'). + - ``format`` -- (string, default: 'A'). OUTPUT: @@ -1103,7 +1103,7 @@ def is_dead(self, warn_only=False): INPUT: - - warn_only - (bool, default: ``False``), whether to warn when the + - warn_only -- (bool, default: ``False``), whether to warn when the sequence is dead instead of returning a boolean. EXAMPLES: @@ -1244,7 +1244,7 @@ def first_terms(self, number=None): INPUT: - - ``number`` - (integer or ``None``, default: ``None``) the number of + - ``number`` -- (integer or ``None``, default: ``None``) the number of terms returned (if less than the number of available terms). When set to None, returns all the known terms. @@ -1307,7 +1307,7 @@ def __call__(self, k): INPUT: - - ``k`` - integer. + - ``k`` -- integer. OUTPUT: @@ -1371,7 +1371,7 @@ def __getitem__(self, i): INPUT: - - ``i`` - integer. + - ``i`` -- integer. OUTPUT: @@ -1514,10 +1514,10 @@ def links(self, browse=None, format='guess'): INPUT: - - ``browse`` - an integer, a list of integers, or the word 'all' + - ``browse`` -- an integer, a list of integers, or the word 'all' (default: ``None``) : which links to open in a web browser. - - ``format`` - string (default: 'guess') : how to display the links. + - ``format`` -- string (default: 'guess') : how to display the links. OUTPUT: @@ -1616,7 +1616,7 @@ def cross_references(self, fetch=False): INPUT: - - ``fetch`` - boolean (default: ``False``). + - ``fetch`` -- boolean (default: ``False``). OUTPUT: From c0d93fcb4df5ed6af2d48934c02b2fe1bc67a323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 16 May 2020 11:21:15 +0200 Subject: [PATCH 199/476] fix latex --- src/sage/databases/oeis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index bbbe5a32a35..f94e4fc0714 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -105,7 +105,7 @@ ... -What does the Taylor expansion of the `e^(e^x-1)` function have to do with +What does the Taylor expansion of the `e^{e^x-1}` function have to do with primes ? :: From edf44cce318f542dc32d246fda1da84a3cebec5a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 May 2020 09:58:49 +1000 Subject: [PATCH 200/476] Speed up multiplication of diagram algebras by avoiding checks. --- src/sage/combinat/diagram_algebras.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 5037c6062fa..06bfda76e2e 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -246,7 +246,7 @@ class AbstractPartitionDiagram(AbstractSetPartition): ... ValueError: {{1, 2}, {3, 4}} does not represent two rows of vertices of order 2 """ - def __init__(self, parent, d): + def __init__(self, parent, d, check=True): r""" Initialize ``self``. @@ -257,7 +257,7 @@ def __init__(self, parent, d): sage: pd1 = da.AbstractPartitionDiagram(pd, ((-2,-1),(1,2)) ) """ self._base_diagram = tuple(sorted(tuple(sorted(i)) for i in d)) - super(AbstractPartitionDiagram, self).__init__(parent, self._base_diagram) + super(AbstractPartitionDiagram, self).__init__(parent, self._base_diagram, check=check) def check(self): r""" @@ -402,7 +402,7 @@ def set_partition(self): """ return SetPartitions()(self) - def compose(self, other): + def compose(self, other, check=True): r""" Compose ``self`` with ``other``. @@ -427,7 +427,7 @@ def compose(self, other): ({{-2, -1}, {1, 2}}, 1) """ (composite_diagram, loops_removed) = set_partition_composition(self._base_diagram, other._base_diagram) - return (self.__class__(self.parent(), composite_diagram), loops_removed) + return (self.__class__(self.parent(), composite_diagram, check=check), loops_removed) def propagating_number(self): r""" @@ -1216,7 +1216,7 @@ def __iter__(self): # treat it like an attribute, so we call the underlying # __func__. for i in self._diagram_func.__func__(self.order): - yield self.element_class(self, i) + yield self.element_class(self, i, check=False) def __contains__(self, obj): r""" @@ -2165,7 +2165,7 @@ def product_on_basis(self, d1, d2): d1 = self._indices(d1) if not self._indices.is_parent_of(d2): d2 = self._indices(d2) - (composite_diagram, loops_removed) = d1.compose(d2) + (composite_diagram, loops_removed) = d1.compose(d2, check=False) return self.term(composite_diagram, self._q**loops_removed) class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): @@ -3088,7 +3088,7 @@ def matchings(A, B): for sigma in Permutations(Y): yield [x.union(y) for x, y in zip(X, sigma)] + restA + restB - D, removed = d1.compose(d2) + D, removed = d1.compose(d2, check=False) only_top = set([frozenset(part) for part in d1 if all(i > 0 for i in part)]) only_bottom = set([frozenset(part) for part in d2 From 5e02fc68e97e18a06949b3bda2e3a39ace990184 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 May 2020 09:52:44 +1000 Subject: [PATCH 201/476] Initial implementation of blob algebras. --- src/doc/en/reference/references/index.rst | 13 + src/sage/algebras/catalog.py | 2 + src/sage/combinat/blob_algebra.py | 590 ++++++++++++++++++++++ 3 files changed, 605 insertions(+) create mode 100644 src/sage/combinat/blob_algebra.py diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 644ac84d23c..48c86767a6a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2349,6 +2349,10 @@ REFERENCES: .. [Gr2007] \J. Green, Polynomial representations of `GL_n`, Springer Verlag, 2007. +.. [Graham1985] \J. Graham, + *Modular representations of Hecke algebras and related algebras*. + PhD thesis, University of Sydney, 1985. + .. [GriRei18] Darij Grinberg, Victor Reiner, *Hopf Algebras in Combinatorics*, :arxiv:`1409.8356v5`. @@ -2770,6 +2774,11 @@ REFERENCES: Science, 447, 74–84 (2012). :doi:`10.1016/j.tcs.2011.11.011` +.. [ILZ2018] \K. Iohara, G. Gehrer, and R. Zhang. + *Schur-Weyl duality for certain infinite dimensional* + `U_q(\mathfrak{sl}_2`-*modules*. + Preprint, :arxiv:`1811.01325` (2018). + .. [IR1990] \K. Ireland and M. Rosen, *A Classical Introduction to Modern Number Theory*, Springer-Verlag, GTM volume 84, 1990. @@ -3867,6 +3876,10 @@ REFERENCES: .. [MS1977] \F. J. MacWilliams, N. J. A. Sloane, *The Theory of Error-Correcting Codes*, North-Holland, Amsterdam, 1977 +.. [MS1994] \P. Martin and H. Saleur. + *The blob algebra and the periodic Temperley-Lieb algebra*. + Lett. Math. Phys., **30** (1994), no. 3. pp. 189-206. + .. [MS2003] \T. Mulders, A. Storjohann, "On lattice reduction for polynomial matrices", J. Symbolic Comput. 35 (2003), no. 4, 377--401 diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index a4423f44267..0e04afc9d76 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -11,6 +11,7 @@ - :class:`algebras.AskeyWilson ` - :class:`algebras.Brauer ` +- :class:`algebras.Blob ` - :class:`algebras.Clifford ` - :class:`algebras.ClusterAlgebra ` - :class:`algebras.Descent ` @@ -99,6 +100,7 @@ lazy_import('sage.combinat.diagram_algebras', 'PartitionAlgebra', 'Partition') lazy_import('sage.combinat.diagram_algebras', 'PlanarAlgebra', 'PlanarPartition') lazy_import('sage.combinat.diagram_algebras', 'TemperleyLiebAlgebra', 'TemperleyLieb') +lazy_import('sage.combinat.blob_algebra', 'BlobAlgebra', 'Blob') lazy_import('sage.combinat.posets.moebius_algebra', 'MoebiusAlgebra', 'Moebius') lazy_import('sage.combinat.free_prelie_algebra', 'FreePreLieAlgebra', 'FreePreLie') lazy_import('sage.combinat.free_dendriform_algebra', 'FreeDendriformAlgebra', 'FreeDendriform') diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py new file mode 100644 index 00000000000..6a7a65245a2 --- /dev/null +++ b/src/sage/combinat/blob_algebra.py @@ -0,0 +1,590 @@ +r""" +Blob Algebras + +AUTHORS: + +- Travis Scrimshaw (2020-05-16): Initial version +""" + +# **************************************************************************** +# Copyright (C) 2020 Travis Scrimshaw +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import Element, get_coercion_model +from sage.structure.richcmp import richcmp +#from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.cachefunc import cached_method +from sage.misc.misc import powerset +from sage.functions.other import binomial +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.algebras import Algebras +from sage.combinat.diagram_algebras import TemperleyLiebDiagrams +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.dyck_word import DyckWords + +#@add_metaclass(InheritComparisonClasscallMetaclass) +class BlobDiagram(Element): + r""" + A blob diagram. + + A blob diagram consists of a perfect matching of the set + `\{1, \ldots, n\} \sqcup \{-1, \ldots, -n\}` such that the result + is a noncrossing matching (a :class:`Temperley-Lieb diagram + `), divided + into two sets of pairs: one for the pairs with blobs and one for + those without. The blobed pairs must either be either the leftmost + propagating strand or to the left of it and not nested. + """ + def __init__(self, parent, marked, unmarked): + r""" + Initialize ``self``. + + TESTS:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: B = BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) + sage: TestSuite(B).run() + """ + Element.__init__(self, parent) + self.marked = tuple(sorted([tuple(sorted(pair)) for pair in marked])) + self.unmarked = tuple(sorted([tuple(sorted(pair)) for pair in unmarked])) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) + ({{-3, 1}}, {{-4, 2}, {-2, -1}, {3, 4}}) + """ + return '({{{}}}, {{{}}})'.format(', '.join('{' + repr(X)[1:-1] + '}' + for X in self.marked), + ', '.join('{' + repr(X)[1:-1] + '}' + for X in self.unmarked)) + + def __hash__(self): + r""" + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: B = BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) + sage: hash(B) in [hash(D) for D in BD4] + True + sage: len(set([hash(D) for D in BD4])) == len(BD4) + True + """ + return hash((self.marked, self.unmarked)) + + def _richcmp_(self, other, op): + r""" + Compare ``self`` to ``other`` with operation ``op``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: B = BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) + sage: any(B == D for D in BD4) + True + sage: B2 = BD4([], [[1,-3], [2,-4], [3,4], [-1,-2]]) + sage: B == B2 + False + sage: B != B2 + True + sage: sorted(BlobDiagrams(3)) + [({}, {{-3, -2}, {-1, 1}, {2, 3}}), + ({}, {{-3, -2}, {-1, 3}, {1, 2}}), + ({}, {{-3, 1}, {-2, -1}, {2, 3}}), + ({}, {{-3, 3}, {-2, -1}, {1, 2}}), + ({}, {{-3, 3}, {-2, 2}, {-1, 1}}), + ({{-3, 1}}, {{-2, -1}, {2, 3}}), + ({{-3, 1}, {-2, -1}}, {{2, 3}}), + ({{-3, 3}}, {{-2, -1}, {1, 2}}), + ({{-3, 3}, {-2, -1}}, {{1, 2}}), + ({{-3, 3}, {-2, -1}, {1, 2}}, {}), + ({{-3, 3}, {1, 2}}, {{-2, -1}}), + ({{-2, -1}}, {{-3, 1}, {2, 3}}), + ({{-2, -1}}, {{-3, 3}, {1, 2}}), + ({{-2, -1}, {1, 2}}, {{-3, 3}}), + ({{-1, 1}}, {{-3, -2}, {2, 3}}), + ({{-1, 1}}, {{-3, 3}, {-2, 2}}), + ({{-1, 3}}, {{-3, -2}, {1, 2}}), + ({{-1, 3}, {1, 2}}, {{-3, -2}}), + ({{1, 2}}, {{-3, -2}, {-1, 3}}), + ({{1, 2}}, {{-3, 3}, {-2, -1}})] + """ + return richcmp((self.marked, self.unmarked), + (other.marked, other.unmarked), + op) + + def temperley_lieb_diagram(self): + r""" + Return the Temperley-Lieb diagram corresponding to ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: B = BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) + sage: B.temperley_lieb_diagram() + {{-4, 2}, {-3, 1}, {-2, -1}, {3, 4}} + """ + return self.parent()._TL_diagrams(self.marked + self.unmarked) + +class BlobDiagrams(Parent, UniqueRepresentation): + """ + The set of all blob diagrams. + """ + def __init__(self, n): + r""" + Initialize ``self``. + + TESTS:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: TestSuite(BD4).run() + """ + self._n = n + self._TL_diagrams = TemperleyLiebDiagrams(n) + Parent.__init__(self, category=FiniteEnumeratedSets()) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BlobDiagrams(4) + Blob diagrams of order 4 + """ + return "Blob diagrams of order {}".format(self._n) + + def cardinality(self): + r""" + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: BD4.cardinality() + 70 + """ + return binomial(2*self._n, self._n) + + def order(self): + r""" + Return the order of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: BD4.order() + 4 + """ + return self._n + + @cached_method + def base_set(self): + r""" + Return the base set of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: sorted(BD4.base_set()) + [-4, -3, -2, -1, 1, 2, 3, 4] + """ + return frozenset(range(1,self._n+1)).union(range(-self._n,0)) + + def _element_constructor_(self, marked, unmarked=None): + r""" + Construct an element of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: BD4([[1,-3]], [[-1,-2], [2,3], [-4,4]]) + ({{-3, 1}}, {{-4, 4}, {-2, -1}, {2, 3}}) + sage: BD4([[(1,-3)], ([-1,-2], (2,3), [-4,4])]) + ({{-3, 1}}, {{-4, 4}, {-2, -1}, {2, 3}}) + """ + if unmarked is None: + marked, unmarked = marked + ret = self.element_class(self, marked, unmarked) + if ret not in self: + raise ValueError("not a blob diagram of order {}".format(self._n)) + return ret + + def __contains__(self, X): + r""" + Check if ``X`` is contained in ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD4 = BlobDiagrams(4) + sage: BD4([[1,-3], [-1,-2]], [[2,-4], [3,4]]) # indirect doctest + ({{-3, 1}, {-2, -1}}, {{-4, 2}, {3, 4}}) + sage: BD4([[1,4], [-1,-2], [-3,-4]], [[2,3]]) # indirect doctest + ({{-4, -3}, {-2, -1}, {1, 4}}, {{2, 3}}) + + sage: BD4([[1,-2], [-1,-3]], [[2,-4], [3,4]]) # crossing strands + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[1,-4], [-1,-2]], [[2,-3], [3,4]]) # crossing strands + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[1,-2], [-1,-3]], [[3,-4], [2,4]]) # crossing strands + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[1,-3], [-1,-2], [3,4]], [[2,-4]]) # trapped blob cup + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[-1,3], [1,2], [-3,-4]], [[-2,4]]) # trapped blob cap + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[1,4], [-1,-2], [-3,-4], [2,3]], []) # nested blob cup + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[-1,-4], [1,2], [3,4], [-2,-3]], []) # nested blob cap + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + sage: BD4([[3,-3]], [[1,-1],[2,-2],[4,-4]]) # trapped propogating line + Traceback (most recent call last): + ... + ValueError: not a blob diagram of order 4 + """ + if not isinstance(X, BlobDiagram): + return False + # Check that it is a Temperley-Lieb diagram + TL = X.marked + X.unmarked # the TL diagram + if TL not in self._TL_diagrams: + return False + # Check left escaping + for x, y in X.marked: + if x > 0: # Must be a cup + for P in TL: + if P[1] < 0: # P is a cap + continue + if P[1] < x: + if P[0] < 0: # A propogating line to the left + return False + else: # Note that P[1] != x + if 0 < P[0] < x: # A nesting line + return False + elif y < 0: # Must be a cap + for P in TL: + if P[0] > 0: # P is a cup + continue + if P[0] > y: + if P[1] > 0: # A propogating line to the left + return False + else: # Note that P[0] != y + if 0 > P[1] > y: # A nesting line + return False + else: # Must be a propogating line + if any(P[0] < 0 and P[1] > 0 and P[1] < y for P in TL): + return False + return True + + def __iter__(self): + r""" + Iterate over ``self``. + + EXAMPLES:: + + sage: from sage.combinat.blob_algebra import BlobDiagrams + sage: BD3 = BlobDiagrams(3) + sage: for b in BD3: b + ({}, {{-3, 3}, {-2, -1}, {1, 2}}) + ({{1, 2}}, {{-3, 3}, {-2, -1}}) + ({{-2, -1}}, {{-3, 3}, {1, 2}}) + ({{-2, -1}, {1, 2}}, {{-3, 3}}) + ({{-3, 3}}, {{-2, -1}, {1, 2}}) + ({{-3, 3}, {1, 2}}, {{-2, -1}}) + ({{-3, 3}, {-2, -1}}, {{1, 2}}) + ({{-3, 3}, {-2, -1}, {1, 2}}, {}) + ({}, {{-3, -2}, {-1, 3}, {1, 2}}) + ({{1, 2}}, {{-3, -2}, {-1, 3}}) + ({{-1, 3}}, {{-3, -2}, {1, 2}}) + ({{-1, 3}, {1, 2}}, {{-3, -2}}) + ({}, {{-3, 1}, {-2, -1}, {2, 3}}) + ({{-3, 1}}, {{-2, -1}, {2, 3}}) + ({{-2, -1}}, {{-3, 1}, {2, 3}}) + ({{-3, 1}, {-2, -1}}, {{2, 3}}) + ({}, {{-3, -2}, {-1, 1}, {2, 3}}) + ({{-1, 1}}, {{-3, -2}, {2, 3}}) + ({}, {{-3, 3}, {-2, 2}, {-1, 1}}) + ({{-1, 1}}, {{-3, 3}, {-2, 2}}) + """ + for D in DyckWords(self._n): + markable = set() + unmarked = [] + unpaired = [] + # Determine the pairing and which pairings are markable + for i,d in enumerate(D): + if i >= self._n: + i = -2*self._n + i + else: + i += 1 + if d == 1: + unpaired.append(i) + else: # d == 0 + m = unpaired.pop() + if not unpaired: + markable.add((m, i)) + else: + unmarked.append((m, i)) + for X in powerset(markable): + yield self.element_class(self, X, unmarked + list(markable.difference(X))) + + Element = BlobDiagram + +class BlobAlgebra(CombinatorialFreeModule): + r""" + The blob algebra. + + The *blob algebra* (also known as the Temperley-Lieb algebra of type `B` + in [ILZ2018]_, but is a quotient of the Temperley-Lieb algebra of type `B` + defined in [Graham1985]_) is a diagram-type algebra introduced in + [MS1994]_ whose basis consists of :class:`Temperley-Lieb diagrams + `, noncrossing + perfect matchings, that may contain blobs on strands that can be + deformed so that the blob touches the left side (which we can think of + as a frozen pole). + + The form we give here has 3 parameters, the natural one from the + :class:`Temperley-Lieb algebra `, + one for the idempotent relation, and one for a loop with a blob. + + INPUT: + + - ``k`` -- the order + - ``q1`` -- the loop parameter + - ``q2`` -- the idempotent parameter + - ``q3`` -- the blob loop parameter + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B4 = algebras.Blob(4, q, r, s) + sage: B = list(B4.basis()) + sage: B[2] + B({{-4, -3}}, {{-2, -1}, {1, 2}, {3, 4}}) + sage: B[4] + B({{3, 4}}, {{-4, -3}, {-2, -1}, {1, 2}}) + sage: B[2] * B[4] + q*r*s*B({}, {{-4, -3}, {-2, -1}, {1, 2}, {3, 4}}) + + REFERENCES: + + - [MS1994]_ + - [ILZ2018]_ + """ + @staticmethod + def __classcall_private__(cls, k, q1, q2, q3, base_ring=None, prefix='B'): + """ + Normalize input to ensure a unique representation. + + TESTS:: + + sage: R. = ZZ[] + sage: B3 = algebras.Blob(3, q, r, s) + sage: Bp = algebras.Blob(3, q, r, s, R, prefix='B') + sage: B3 is Bp + True + """ + if base_ring is None: + base_ring = get_coercion_model().common_parent(q1, q2, q3) + q1 = base_ring(q1) + q2 = base_ring(q2) + q3 = base_ring(q3) + return super(BlobAlgebra, cls).__classcall__(cls, k, q1, q2, q3, base_ring, prefix) + + def __init__(self, k, q1, q2, q3, base_ring, prefix): + """ + Initialize ``self``. + + TESTS:: + + sage: R. = ZZ[] + sage: B4 = algebras.Blob(4, q, r, s) + sage: TestSuite(B4).run() + + sage: B3 = algebras.Blob(3, q, r, s) + sage: B = list(B3.basis()) + sage: TestSuite(B3).run(elements=B) # long time + """ + self._q1 = q1 + self._q2 = q2 + self._q3 = q3 + diagrams = BlobDiagrams(k) + cat = Algebras(base_ring.category()).FiniteDimensional().WithBasis() + CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=cat, + prefix=prefix, bracket=False) + + def order(self): + """ + Return the order of ``self``. + + The order of a partition algebra is defined as half of the number + of nodes in the diagrams. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B4 = algebras.Blob(4, q, r, s) + sage: B4.order() + 4 + """ + return self._indices.order() + + @cached_method + def one_basis(self): + r""" + Return the index of the basis element `1`. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B4 = algebras.Blob(4, q, r, s) + sage: B4.one_basis() + ({}, {{-4, 4}, {-3, 3}, {-2, 2}, {-1, 1}}) + """ + B = self._indices + return B.element_class(B, [], [[i, -i] for i in range(1, self.order()+1)]) + + def product_on_basis(self, top, bot): + """ + Return the product of the basis elements indexed by ``top`` + and ``bot``. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B4 = algebras.Blob(4, q, r, s) + sage: B = B4.basis() + sage: BD = B.keys() + sage: BD[2] + ({{-4, -3}}, {{-2, -1}, {1, 2}, {3, 4}}) + sage: BD[4] + ({{3, 4}}, {{-4, -3}, {-2, -1}, {1, 2}}) + sage: B4.product_on_basis(BD[2], BD[4]) + q*r*s*B({}, {{-4, -3}, {-2, -1}, {1, 2}, {3, 4}}) + sage: all(len((x*y).support()) == 1 for x in B for y in B) + True + """ + ret_lists = [[], []] + coeff = self.base_ring().one() + top_marked = set(top.marked) + top_unmarked = set(top.unmarked) + bot_marked = set(bot.marked) + bot_unmarked = set(bot.unmarked) + + for top_set, is_unmarked in [(top_marked, 0), (top_unmarked, 1)]: + while top_set: + # We are starting a new strand + cur, stop = top_set.pop() # note that cur < stop + unmarked = is_unmarked + #print(top_set, unmarked, cur, stop) + if cur > 0: # Both are anchored to the top + ret_lists[unmarked].append((cur, stop)) + continue + anchored = bool(stop > 0) # Possibly only stop is anchored + + # Follow the path from cur until we either reach stop or + # we break out of the loop because both ends are anchored + while anchored or cur != stop: + #print(anchored, unmarked, cur, stop) + cur = -cur # Move cur to the bottom diagram + for X in bot_marked: + if cur in X: + if unmarked: + unmarked = 0 + else: + coeff *= self._q2 + prev = cur + cur = X[1-X.index(prev)] + bot_marked.remove(X) + break + for X in bot_unmarked: + if cur in X: + prev = cur + cur = X[1-X.index(prev)] + bot_unmarked.remove(X) + break + if cur < 0: # cur is anchored at the bottom + if anchored: + ret_lists[unmarked].append((stop, cur)) + break + else: + anchored = True + stop, cur = cur, stop # stop is now anchored to the bottom + continue + cur = -cur # bring cur back to the top diagram + for X in top_marked: + if cur in X: + if unmarked: + unmarked = 0 + else: + coeff *= self._q2 + prev = cur + cur = X[1-X.index(prev)] + top_marked.remove(X) + break + for X in top_unmarked: + if cur in X: + prev = cur + cur = X[1-X.index(prev)] + top_unmarked.remove(X) + break + if cur > 0: # cur is anchored at the top + if anchored: + ret_lists[unmarked].append((stop, cur)) + break + else: + anchored = True + stop, cur = cur, stop # stop is now anchored to the top + if cur == stop: # We have found a (marked) loop + if unmarked: + coeff *= self._q1 + else: + coeff *= self._q3 + # Everything remaining in the bottom sets are just anchored + # at the bottom, (i.e., are of the form {-i, -j}). + ret_lists[0].extend(bot_marked) + ret_lists[1].extend(bot_unmarked) + + if coeff == 0: + return self.zero() + diagram = self._indices.element_class(self._indices, ret_lists[0], ret_lists[1]) + return self._from_dict({diagram: coeff}, remove_zeros=False) + From 53f0359017fc1909498de22c4c4b8c5310e76bdb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 May 2020 20:01:00 -0700 Subject: [PATCH 202/476] src/sage/env.py (sage_include_directories): Do not put SAGE_INC in front of the sage source include directories --- src/sage/env.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 18d86fe6c49..5ecec20f105 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -364,8 +364,7 @@ def sage_include_directories(use_sources=False): TOP = SAGE_SRC if use_sources else SAGE_LIB - return [SAGE_INC, - TOP, + return [TOP, os.path.join(TOP, 'sage', 'ext'), distutils.sysconfig.get_python_inc(), numpy.get_include()] From 16247ad9675343f1d3e1158cc5e43137aec82645 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 May 2020 20:01:37 -0700 Subject: [PATCH 203/476] src/setup.py: Do not put SAGE_LOCAL/lib in front of the library directories --- src/setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/setup.py b/src/setup.py index 8025a3d0c89..d8b700e9b12 100755 --- a/src/setup.py +++ b/src/setup.py @@ -83,11 +83,12 @@ def excepthook(*exc): keep_going = False -# search for dependencies and add to gcc -I +# Search for dependencies in the source tree and add to gcc -I include_dirs = sage_include_directories(use_sources=True) -# Look for libraries in $SAGE_LOCAL/lib -library_dirs = [os.path.join(SAGE_LOCAL, "lib")] +# Look for libraries only in what is configured already through distutils +# and environment variables +library_dirs = [] # Manually add -fno-strict-aliasing, which is needed to compile Cython # and disappears from the default flags if the user has set CFLAGS. From fb4cb464afe1d91051efc36b15e3e7dfb7cd3b07 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 May 2020 13:08:12 +1000 Subject: [PATCH 204/476] Slightly abstracting the latex code for diagrams to use in blob algebra. --- src/sage/combinat/blob_algebra.py | 83 ++++++++++--- src/sage/combinat/diagram_algebras.py | 162 +++++++++++++++----------- 2 files changed, 163 insertions(+), 82 deletions(-) diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 6a7a65245a2..fb2fee244bc 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -26,7 +26,7 @@ from sage.functions.other import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.algebras import Algebras -from sage.combinat.diagram_algebras import TemperleyLiebDiagrams +from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex) from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.dyck_word import DyckWords @@ -113,23 +113,23 @@ def _richcmp_(self, other, op): ({}, {{-3, 3}, {-2, -1}, {1, 2}}), ({}, {{-3, 3}, {-2, 2}, {-1, 1}}), ({{-3, 1}}, {{-2, -1}, {2, 3}}), - ({{-3, 1}, {-2, -1}}, {{2, 3}}), ({{-3, 3}}, {{-2, -1}, {1, 2}}), - ({{-3, 3}, {-2, -1}}, {{1, 2}}), - ({{-3, 3}, {-2, -1}, {1, 2}}, {}), - ({{-3, 3}, {1, 2}}, {{-2, -1}}), ({{-2, -1}}, {{-3, 1}, {2, 3}}), ({{-2, -1}}, {{-3, 3}, {1, 2}}), - ({{-2, -1}, {1, 2}}, {{-3, 3}}), ({{-1, 1}}, {{-3, -2}, {2, 3}}), ({{-1, 1}}, {{-3, 3}, {-2, 2}}), ({{-1, 3}}, {{-3, -2}, {1, 2}}), - ({{-1, 3}, {1, 2}}, {{-3, -2}}), ({{1, 2}}, {{-3, -2}, {-1, 3}}), - ({{1, 2}}, {{-3, 3}, {-2, -1}})] + ({{1, 2}}, {{-3, 3}, {-2, -1}}), + ({{-3, 1}, {-2, -1}}, {{2, 3}}), + ({{-3, 3}, {-2, -1}}, {{1, 2}}), + ({{-3, 3}, {1, 2}}, {{-2, -1}}), + ({{-2, -1}, {1, 2}}, {{-3, 3}}), + ({{-1, 3}, {1, 2}}, {{-3, -2}}), + ({{-3, 3}, {-2, -1}, {1, 2}}, {})] """ - return richcmp((self.marked, self.unmarked), - (other.marked, other.unmarked), + return richcmp((len(self.marked), self.marked, self.unmarked), + (len(other.marked), other.marked, other.unmarked), op) def temperley_lieb_diagram(self): @@ -147,7 +147,7 @@ def temperley_lieb_diagram(self): return self.parent()._TL_diagrams(self.marked + self.unmarked) class BlobDiagrams(Parent, UniqueRepresentation): - """ + r""" The set of all blob diagrams. """ def __init__(self, n): @@ -411,7 +411,7 @@ class BlobAlgebra(CombinatorialFreeModule): """ @staticmethod def __classcall_private__(cls, k, q1, q2, q3, base_ring=None, prefix='B'): - """ + r""" Normalize input to ensure a unique representation. TESTS:: @@ -430,7 +430,7 @@ def __classcall_private__(cls, k, q1, q2, q3, base_ring=None, prefix='B'): return super(BlobAlgebra, cls).__classcall__(cls, k, q1, q2, q3, base_ring, prefix) def __init__(self, k, q1, q2, q3, base_ring, prefix): - """ + r""" Initialize ``self``. TESTS:: @@ -451,8 +451,61 @@ def __init__(self, k, q1, q2, q3, base_ring, prefix): CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=cat, prefix=prefix, bracket=False) - def order(self): + def _latex_term(self, diagram): + r""" + Return a latex representation of ``diagram``. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B2 = algebras.Blob(2, q, r, s) + sage: latex(B2.an_element()) + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 3\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[blue,very thick] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. node[midway,circle,fill,scale=0.6] {} (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \draw[blue,very thick] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. node[midway,circle,fill,scale=0.6] {} (G-2); + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \end{tikzpicture} """ + def edge_options(P): + if P[1] < P[0]: + P = [P[1], P[0]] + if tuple(P) in diagram.marked: + return 'blue,very thick' + return '' + def edge_additions(P): + if P[1] < P[0]: + P = [P[1], P[0]] + if tuple(P) in diagram.marked: + return 'node[midway,circle,fill,scale=0.6] {} ' + return '' + return diagram_latex(diagram.marked+diagram.unmarked, + edge_options=edge_options, + edge_additions=edge_additions) + + def order(self): + r""" Return the order of ``self``. The order of a partition algebra is defined as half of the number @@ -483,7 +536,7 @@ def one_basis(self): return B.element_class(B, [], [[i, -i] for i in range(1, self.order()+1)]) def product_on_basis(self, top, bot): - """ + r""" Return the product of the basis elements indexed by ``top`` and ``bot``. diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 5037c6062fa..a259d23a177 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1998,8 +1998,8 @@ def _latex_term(self, diagram): \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \draw (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); - \draw (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); \end{tikzpicture} sage: latex(P.orbit_basis()([[1,2],[-2,-1]])) # indirect doctest @@ -2009,73 +2009,11 @@ def _latex_term(self, diagram): \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw, fill] {}; \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw, fill] {}; \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw, fill] {}; - \draw (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); - \draw (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); \end{tikzpicture} - """ - # these allow the view command to work (maybe move them - # somewhere more appropriate?) - from sage.misc.latex import latex - latex.add_to_mathjax_avoid_list('tikzpicture') - latex.add_package_to_preamble_if_available('tikz') - if hasattr(self, '_fill'): - filled_str = ", fill" - else: - filled_str = "" - - def sgn(x): - # Define the sign function - if x > 0: - return 1 - if x < 0: - return -1 - return 0 - l1 = [] # list of blocks - l2 = [] # list of nodes - for i in list(diagram): - l1.append(list(i)) - for j in list(i): - l2.append(j) - output = "\\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \n" #setup beginning of picture - for i in l2: #add nodes - output = output + "\\node[vertex] (G-{}) at ({}, {}) [shape = circle, draw{}] {{}}; \n".format(i, (abs(i)-1)*1.5, sgn(i), filled_str) - for i in l1: #add edges - if len(i) > 1: - l4 = list(i) - posList = [] - negList = [] - for j in l4: # sort list so rows are grouped together - if j > 0: - posList.append(j) - elif j < 0: - negList.append(j) - posList.sort() - negList.sort() - l4 = posList + negList - l5 = l4[:] #deep copy - for j in range(len(l5)): - l5[j-1] = l4[j] #create a permuted list - if len(l4) == 2: - l4.pop() - l5.pop() #pops to prevent duplicating edges - for j in zip(l4, l5): - xdiff = abs(j[1])-abs(j[0]) - y1 = sgn(j[0]) - y2 = sgn(j[1]) - if y2-y1 == 0 and abs(xdiff) < 5: #if nodes are close to each other on same row - diffCo = (0.5+0.1*(abs(xdiff)-1)) #gets bigger as nodes are farther apart; max value of 1; min value of 0.5. - outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1) - inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2) - elif y2-y1 != 0 and abs(xdiff) == 1: #if nodes are close enough curviness looks bad. - outVec = (sgn(xdiff)*0.75, -1*y1) - inVec = (-1*sgn(xdiff)*0.75, -1*y2) - else: - outVec = (sgn(xdiff)*1, -1*y1) - inVec = (-1*sgn(xdiff), -1*y2) - output = output + "\\draw (G-{}) .. controls +{} and +{} .. (G-{}); \n".format(j[0], outVec, inVec, j[1]) - output = output + "\\end{tikzpicture} \n" #end picture - return output + return diagram_latex(diagram, fill=hasattr(self, '_fill')) # The following subclass provides a few additional methods for # (sub)partition algebra elements. @@ -3767,6 +3705,96 @@ def __pow__(self, n): raise ValueError("can only take positive integer powers") return generic_power(self, n) +def diagram_latex(diagram, fill=False, edge_options=None, edge_additions=None): + r""" + Return latex code for the diagram ``diagram`` using tikz. + + EXAMPLES:: + + sage: from sage.combinat.diagram_algebras import PartitionDiagrams, diagram_latex + sage: P = PartitionDiagrams(2) + sage: D = P([[1,2],[-2,-1]]) + sage: print(diagram_latex(D)) # indirect doctest + \begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + """ + # these allow the view command to work (maybe move them + # somewhere more appropriate?) + from sage.misc.latex import latex + latex.add_to_mathjax_avoid_list('tikzpicture') + latex.add_package_to_preamble_if_available('tikz') + + if fill: + filled_str = ", fill" + else: + filled_str = "" + + if edge_options is None: + edge_options = lambda P: '' + if edge_additions is None: + edge_additions = lambda P: '' + + def sgn(x): + # Define the sign function + if x > 0: + return 1 + if x < 0: + return -1 + return 0 + l1 = [] # list of blocks + l2 = [] # list of nodes + for i in list(diagram): + l1.append(list(i)) + for j in list(i): + l2.append(j) + output = "\\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \n" #setup beginning of picture + for i in l2: #add nodes + output = output + "\\node[vertex] (G-{}) at ({}, {}) [shape = circle, draw{}] {{}}; \n".format(i, (abs(i)-1)*1.5, sgn(i), filled_str) + for i in l1: #add edges + if len(i) > 1: + l4 = list(i) + posList = [] + negList = [] + for j in l4: # sort list so rows are grouped together + if j > 0: + posList.append(j) + elif j < 0: + negList.append(j) + posList.sort() + negList.sort() + l4 = posList + negList + l5 = l4[:] #deep copy + for j in range(len(l5)): + l5[j-1] = l4[j] #create a permuted list + if len(l4) == 2: + l4.pop() + l5.pop() #pops to prevent duplicating edges + for j in zip(l4, l5): + xdiff = abs(j[1])-abs(j[0]) + y1 = sgn(j[0]) + y2 = sgn(j[1]) + if y2-y1 == 0 and abs(xdiff) < 5: #if nodes are close to each other on same row + diffCo = (0.5+0.1*(abs(xdiff)-1)) #gets bigger as nodes are farther apart; max value of 1; min value of 0.5. + outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1) + inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2) + elif y2-y1 != 0 and abs(xdiff) == 1: #if nodes are close enough curviness looks bad. + outVec = (sgn(xdiff)*0.75, -1*y1) + inVec = (-1*sgn(xdiff)*0.75, -1*y2) + else: + outVec = (sgn(xdiff)*1, -1*y1) + inVec = (-1*sgn(xdiff), -1*y2) + output = output + "\\draw[{}] (G-{}) .. controls +{} and +{} .. {}(G-{}); \n".format( + edge_options(j), j[0], outVec, inVec, edge_additions(j), j[1]) + output = output + "\\end{tikzpicture}" #end picture + return output + ######################################################################### # START BORROWED CODE ######################################################################### From 9a50cba23abb1c6ff4b022c62624da800b88e282 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 May 2020 20:31:06 -0700 Subject: [PATCH 205/476] src/sage/env.py (sage_include_directories): Fixup doctest --- src/sage/env.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 5ecec20f105..4579f21c46e 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -342,8 +342,7 @@ def sage_include_directories(use_sources=False): sage: import sage.env sage: sage.env.sage_include_directories() - ['.../include', - '.../python.../site-packages/sage/ext', + ['.../python.../site-packages/sage/ext', '.../include/python...', '.../python.../numpy/core/include'] From f33b09b73c081bd0ced2fc79c9fa7d06570cd325 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 May 2020 14:35:54 +1000 Subject: [PATCH 206/476] Implementation of the cohomology ring of a RAAG. --- src/doc/en/reference/references/index.rst | 4 + src/sage/groups/raag.py | 317 ++++++++++++++++++++++ 2 files changed, 321 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 644ac84d23c..a13c939349c 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1154,6 +1154,10 @@ REFERENCES: .. [Car1972] \R. W. Carter. *Simple groups of Lie type*, volume 28 of Pure and Applied Mathematics. John Wiley and Sons, 1972. +.. [CQ2019] \A. Cassella and C. Quadrelli. + *Right-angled Artin groups and enhanced Koszul properties*. + Preprint, :arxiv:`1907.03824`, (2019). + .. [CS1996] \G. Call and J. Silverman. Computing the Canonical Height on K3 Surfaces. Mathematics of Comp. , 65 (1996), 259-290. diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index dbe06b18494..982416d96dd 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Right-Angled Artin Groups @@ -35,6 +36,16 @@ from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.combinat.root_system.coxeter_group import CoxeterGroup +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.combinat.free_module import CombinatorialFreeModule +from sage.categories.fields import Fields +from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.algebras.clifford_algebra import CliffordAlgebraElement +from sage.typeset.ascii_art import ascii_art +from sage.typeset.unicode_art import unicode_art + class RightAngledArtinGroup(ArtinGroup): r""" The right-angled Artin group defined by a graph `G`. @@ -369,6 +380,23 @@ def _normal_form(self, word): pos += len(comm_set) return tuple(w) + def cohomology(self, F=None): + """ + Return the cohomology ring of ``self`` over the field ``F``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: A.cohomology() + Cohomology ring of Right-angled Artin group of Cycle graph + with coefficients in Rational Field + """ + if F is None: + from sage.rings.rational_field import QQ + F = QQ + return CohomologyRAAG(F, self) + class Element(ArtinGroupElement): """ An element of a right-angled Artin group (RAAG). @@ -568,3 +596,292 @@ def _richcmp_(self, other, op): """ return richcmp(self._data, other._data, op) +class CohomologyRAAG(CombinatorialFreeModule): + r""" + The cohomology ring of a right-angled Artin group. + + The cohomology ring of a right-angled Artin group `A`, defined by + the graph `G`, with coefficients in a field `F` is isomorphic to + the exterior algebra of `F^N`, where `N` is the number of vertices + in `G`, modulo the quadratic relations `e_i \wedge e_j = 0` if and + only if `(i, j)` is an edge in `G`. This algebra is sometimes also + known as the Cartier-Foata algebra. + + REFERENCES: + + - [CQ2019]_ + """ + def __init__(self, R, A): + """ + Initialize ``self``. + + TESTS:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: TestSuite(H).run() + """ + if R not in Fields(): + raise NotImplementedError("only implemented with coefficients in a field") + self._group = A + + names = tuple(['e' + name[1:] for name in A.variable_names()]) + from sage.graphs.independent_sets import IndependentSets + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + indices = [tuple(ind_set) for ind_set in IndependentSets(A._graph)] + indices = FiniteEnumeratedSet(indices) + cat = AlgebrasWithBasis(R.category()).Super().Graded().FiniteDimensional() + CombinatorialFreeModule.__init__(self, R, indices, category=cat, prefix='H') + self._assign_names(names) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: A.cohomology() + Cohomology ring of Right-angled Artin group of Cycle graph + with coefficients in Rational Field + """ + return "Cohomology ring of {} with coefficients in {}".format(self._group, self.base_ring()) + + def _repr_term(self, m): + """ + Return a string representation of the basis element indexed by + ``m``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H._repr_term((0,1,3)) + 'e0*e1*e3' + sage: w,x,y,z = H.algebra_generators() + sage: y*w + x*z + -e0*e2 + e1*e3 + """ + if len(m) == 0: + return '1' + term = '' + V = self + for i in m: + if len(term) != 0: + term += '*' + term += 'e' + str(i) + return term + + def _ascii_art_term(self, m): + r""" + Return ascii art for the basis element indexed by ``m``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H._ascii_art_term((0,1,3)) + e0/\e1/\e3 + sage: w,x,y,z = H.algebra_generators() + sage: ascii_art(y*w + 2*x*z) + -e0/\e2 + 2*e1/\e3 + """ + if len(m) == 0: + return ascii_art('1') + wedge = '/\\' + return ascii_art(*['e' + str(i) for i in m], sep=wedge) + + def _unicode_art_term(self, m): + """ + Return unicode art for the basis element indexed by ``m``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H._unicode_art_term((0,1,3)) + e0∧e1∧e3 + sage: w,x,y,z = H.algebra_generators() + sage: unicode_art(y*w + x*z) + -e0∧e2 + e1∧e3 + """ + if len(m) == 0: + return unicode_art('1') + import unicodedata + wedge = unicodedata.lookup('LOGICAL AND') + return unicode_art(*['e' + str(i) for i in m], sep=wedge) + + def _latex_term(self, m): + r""" + Return a `\LaTeX` representation of the basis element indexed + by ``m``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H._latex_term((0,1,3)) + ' e_{0} \\wedge e_{1} \\wedge e_{3}' + """ + if len(m) == 0: + return '1' + term = '' + from sage.misc.latex import latex + for i in m: + if len(term) != 0: + term += ' \\wedge' + term += ' e_{{{}}}'.format(latex(i)) + return term + + def gen(self, i): + """ + Return the ``i``-th standard generator of the algebra ``self``. + + This corresponds to the ``i``-th vertex in the graph + (under a fixed ordering of the vertices). + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H.gen(0) + e0 + sage: H.gen(1) + e1 + """ + return self._from_dict({(i,): self.base_ring().one()}, remove_zeros=False) + + @cached_method + def one_basis(self): + """ + Return the basis element indexing `1` of ``self``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H.one_basis() + () + """ + return () + + @cached_method + def algebra_generators(self): + """ + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H.algebra_generators() + Finite family {0: e0, 1: e1, 2: e2, 3: e3} + """ + V = self._group._graph.vertices() + d = {x: self.gen(i) for i,x in enumerate(V)} + from sage.sets.family import Family + return Family(V, lambda x: d[x]) + + def gens(self): + r""" + Return the generators of ``self`` (as an algebra). + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H.gens() + (e0, e1, e2, e3) + """ + return tuple(self.algebra_generators()) + + def ngens(self): + """ + Return the number of algebra generators of ``self``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: H.ngens() + 4 + """ + return self._group._graph.num_verts() + + def degree_on_basis(self, I): + """ + Return the degree on the basis element ``clique``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: sorted([H.degree_on_basis(I) for I in H.basis().keys()]) + [0, 1, 1, 1, 1, 2, 2] + """ + return len(I) + + class Element(CliffordAlgebraElement): + """ + An element in the cohomology ring of a right-angled Artin group. + """ + def _mul_(self, other): + """ + Return ``self`` multiplied by ``other``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: b = sum(H.basis()) + sage: b * b + 2*e0*e2 + 2*e1*e3 + 2*e0 + 2*e1 + 2*e2 + 2*e3 + 1 + """ + zero = self.parent().base_ring().zero() + I = self.parent()._indices + d = {} + + for ml,cl in self: + for mr,cr in other: + # Create the next term + t = list(mr) + for i in reversed(ml): + pos = 0 + for j in t: + if i == j: + pos = None + break + if i < j: + break + pos += 1 + cr = -cr + if pos is None: + t = None + break + t.insert(pos, i) + + if t is None: # The next term is 0, move along + continue + + t = tuple(t) + if t not in I: # not an independent set, so this term is also 0 + continue + d[t] = d.get(t, zero) + cl * cr + if d[t] == zero: + del d[t] + + return self.__class__(self.parent(), d) + From 1709daffedc00828e7658c8b51a9481d6192ddb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 May 2020 11:08:56 +0200 Subject: [PATCH 207/476] spring cleanup for partition tuples, replace gp call by pari call --- src/sage/combinat/partition_tuple.py | 173 ++++++++++++++------------- 1 file changed, 93 insertions(+), 80 deletions(-) diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index a78798746a1..45b75b582e6 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -244,7 +244,7 @@ class of modules for the algebras, which are generalisations of the Specht """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Andrew Mathas # # This program is free software: you can redistribute it and/or modify @@ -252,11 +252,9 @@ class of modules for the algebras, which are generalisations of the Specht # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from __future__ import print_function, absolute_import -from six.moves import range - import itertools from .combinat import CombinatorialElement @@ -266,7 +264,7 @@ class of modules for the algebras, which are generalisations of the Specht from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.interfaces.all import gp +from sage.libs.pari.all import pari from sage.misc.cachefunc import cached_method from sage.rings.all import NN, ZZ, IntegerModRing from sage.rings.integer import Integer @@ -274,10 +272,11 @@ class of modules for the algebras, which are generalisations of the Specht from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation - -#-------------------------------------------------- +# ------------------------------------------------- # Partition tuple - element class -#-------------------------------------------------- +# ------------------------------------------------- + + class PartitionTuple(CombinatorialElement): r""" A tuple of :class:`Partition`. @@ -556,7 +555,7 @@ def _repr_list(self): sage: PartitionTuple(([2,1],[3,2],[1,1,1]))._repr_list() '([2, 1], [3, 2], [1, 1, 1])' """ - return '('+', '.join(nu._repr_() for nu in self)+')' + return '(' + ', '.join(nu._repr_() for nu in self) + ')' def _repr_exp_low(self): """ @@ -615,12 +614,11 @@ def _repr_compact_high(self): return '%s' % '|'.join(mu._repr_compact_high() for mu in self) # override default string representation which is str(self._list) - __str__=lambda self: self._repr_() - + __str__ = lambda self: self._repr_() def _latex_(self): r""" - Returns a LaTeX version of ``self``. + Return a LaTeX version of ``self``. For more on the latex options, see :meth:`Partitions.option`. @@ -688,7 +686,8 @@ def _latex_young_diagram(self): sage: mu = PartitionTuple([[2, 1],[1,1,1]])._latex_young_diagram() """ from sage.combinat.output import tex_from_array_tuple - return tex_from_array_tuple([ [["\\phantom{x}"]*row for row in mu] for mu in self._list ]) + return tex_from_array_tuple([[["\\phantom{x}"] * row for row in mu] + for mu in self._list]) def _latex_diagram(self): """ @@ -700,7 +699,8 @@ def _latex_diagram(self): """ entry = self.parent().options("latex_diagram_str") from sage.combinat.output import tex_from_array_tuple - return tex_from_array_tuple([ [[entry]*row for row in mu] for mu in self._list ], with_lines=False) + return tex_from_array_tuple([[[entry] * row for row in mu] + for mu in self._list], with_lines=False) def _latex_list(self): """ @@ -720,8 +720,10 @@ def _latex_exp_low(self): sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_low() """ - return '(%s)' % '|'.join(','.join('%s%s'%(a+1,'' if e==1 else '^{%s}'%e) - for (a,e) in enumerate(mu)) for mu in self.to_exp()) + txt = '|'.join(','.join('%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) + for a, e in enumerate(mu)) + for mu in self.to_exp()) + return '(' + txt + ')' def _latex_exp_high(self): """ @@ -731,9 +733,10 @@ def _latex_exp_high(self): sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_high() """ - return '(%s)' % '|'.join(','.join(['%s%s'%(a+1,'' if e==1 else '^{%s}'%e) - for (a,e) in enumerate(mu)][::-1]) for mu in self.to_exp()) - + txt = '|'.join(','.join(['%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) + for a, e in enumerate(mu)][::-1]) + for mu in self.to_exp()) + return '(' + txt + ')' def components(self): r""" @@ -760,8 +763,7 @@ def components(self): *** ** """ - return [ t for t in self ] - + return [t for t in self] def diagram(self): r""" @@ -786,7 +788,7 @@ def diagram(self): *** ** - * sage: PartitionTuples.options._reset() """ - col_len = [len(mu)>0 and mu[0] or 1 for mu in self] # columns per component + col_len = [mu and mu[0] or 1 for mu in self] # columns per component row_max = max(len(mu) for mu in self) # maximum row length # There should be a fancier list compression for this but I couldn't get # one to work in the cases where a component was the empty partition @@ -809,7 +811,6 @@ def diagram(self): ferrers_diagram = diagram - def pp(self): r""" Pretty prints this partition tuple. See :meth:`diagram`. @@ -824,7 +825,6 @@ def pp(self): """ print(self.diagram()) - def size(self): """ Return the size of a partition tuple. @@ -945,7 +945,7 @@ def cells(self): def content(self, k,r,c, multicharge): r""" - Returns the content of the cell. + Return the content of the cell. Let `m_k =` ``multicharge[k]``, then the content of a cell is `m_k + c - r`. @@ -1004,8 +1004,10 @@ def content_tableau(self,multicharge): 2 """ from sage.combinat.tableau_tuple import TableauTuple - return TableauTuple([[[multicharge[k]-r+c for c in range(self[k][r])] - for r in range(len(self[k]))] for k in range(len(self))]) + return TableauTuple([[[multicharge[k] - r + c + for c in range(self[k][r])] + for r in range(len(self[k]))] + for k in range(len(self))]) def conjugate(self): """ @@ -1018,7 +1020,6 @@ def conjugate(self): sage: PartitionTuple([[2,1],[1],[1,1,1]]).conjugate() ([3], [1], [2, 1]) - """ return PartitionTuple([nu.conjugate() for nu in self[::-1]]) @@ -1056,22 +1057,25 @@ def dominates(self, mu): except ValueError: raise ValueError('%s must be a PartitionTuple' % mu) - if mu==self: return True - level=0 - ssum=0 # sum of successive rows in self - musum=0 # sum of successive rows in self + if mu == self: + return True + level = 0 + ssum = 0 # sum of successive rows in self + musum = 0 # sum of successive rows in self while levelssum: return False + if musum>ssum: + return False row+=1 if rowssum: return False + if musum>ssum: + return False level+=1 return True @@ -1247,12 +1251,14 @@ def top_garnir_tableau(self,e,cell): g=self.garnir_tableau(cell) - if e==0: return # no more dominant tableau of the same residue + if e==0: + return # no more dominant tableau of the same residue a=e*int((self[comp][row]-col)/e) # number of cells in the e-bricks in row `row` b=e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` - if a==0 or b==0: return self.garnir_tableau(cell) + if a==0 or b==0: + return self.garnir_tableau(cell) t=g.to_list() m=t[comp][row+1][0] # smallest number of 0-Garnir belt @@ -1327,7 +1333,7 @@ def leg_length(self, k,r,c): def contains(self, mu): r""" - Returns ``True`` if this partition tuple contains `\mu`. + Return ``True`` if this partition tuple contains `\mu`. If `\lambda=(\lambda^{(1)}, \ldots, \lambda^{(l)})` and `\mu=(\mu^{(1)}, \ldots, \mu^{(m)})` are two partition tuples then @@ -1379,7 +1385,7 @@ def to_exp(self, k=0): def removable_cells(self): """ - Returns a list of the removable cells of this partition tuple. + Return a list of the removable cells of this partition tuple. All indices are of the form ``(k, r, c)``, where ``r`` is the row-index, ``c`` is the column index and ``k`` is the component. @@ -1415,7 +1421,7 @@ def addable_cells(self): outside_corners = addable_cells # for compatibility with partitions - def add_cell(self, k,r,c): + def add_cell(self, k, r, c): r""" Return the partition tuple obtained by adding a cell in row ``r``, column ``c``, and component ``k``. @@ -1426,17 +1432,18 @@ def add_cell(self, k,r,c): sage: PartitionTuple([[1,1],[4,3],[2,1,1]]).add_cell(0,0,1) ([2, 1], [4, 3], [2, 1, 1]) - """ - if (k,r,c) in self.addable_cells(): # an addable cell - mu=self.to_list() - if c==0: mu[k].append(1) - else: mu[k][r]+=1 + if (k, r, c) in self.addable_cells(): # an addable cell + mu = self.to_list() + if c == 0: + mu[k].append(1) + else: + mu[k][r] += 1 return PartitionTuple(mu) else: - raise ValueError("%s is not an addable cell"%((k,r,c),)) + raise ValueError("%s is not an addable cell" % ((k, r, c),)) - def remove_cell(self, k,r,c): + def remove_cell(self, k, r, c): """ Return the partition tuple obtained by removing a cell in row ``r``, column ``c``, and component ``k``. @@ -1447,14 +1454,13 @@ def remove_cell(self, k,r,c): sage: PartitionTuple([[1,1],[4,3],[2,1,1]]).remove_cell(0,1,0) ([1], [4, 3], [2, 1, 1]) - """ - if (k,r,c) in self.removable_cells(): # a removable cell - mu=self.to_list() - mu[k][r]-=1 + if (k, r, c) in self.removable_cells(): # a removable cell + mu = self.to_list() + mu[k][r] -= 1 return PartitionTuple(mu) else: - raise ValueError("%s is not a removable cell"%((k,r,c),)) + raise ValueError("%s is not a removable cell" % ((k, r, c),)) def to_list(self): r""" @@ -1470,7 +1476,7 @@ def to_list(self): sage: all(mu==PartitionTuple(mu.to_list()) for mu in PartitionTuples(4,4)) True """ - return [ mu.to_list() for mu in self] + return [mu.to_list() for mu in self] def young_subgroup(self): """ @@ -1482,14 +1488,14 @@ def young_subgroup(self): sage: PartitionTuple([[2,1],[4,2],[1]]).young_subgroup() Permutation Group with generators [(), (8,9), (6,7), (5,6), (4,5), (1,2)] """ - gens=[] - m=0 + gens = [] + m = 0 for comp in self: for row in comp: - gens.extend([(c,c+1) for c in range(m+1,m+row)]) - m+=row - gens.append(list(range(1,self.size()+1))) # to ensure we get a subgroup of Sym_n - return PermutationGroup( gens ) + gens.extend([(c, c+1) for c in range(m+1, m+row)]) + m += row + gens.append(list(range(1, self.size()+1))) # to ensure we get a subgroup of Sym_n + return PermutationGroup(gens) def young_subgroup_generators(self): """ @@ -1501,12 +1507,12 @@ def young_subgroup_generators(self): sage: PartitionTuple([[2,1],[4,2],[1]]).young_subgroup_generators() [1, 4, 5, 6, 8] """ - gens=[] - m=0 + gens = [] + m = 0 for comp in self: for row in comp: - gens.extend([c for c in range(m+1,m+row)]) - m+=row + gens.extend([c for c in range(m + 1, m + row)]) + m += row return gens @cached_method @@ -1759,9 +1765,11 @@ def defect(self, e, multicharge): return (sum(beta.get(r, 0) for r in multicharge) - sum(beta[r]**2 - beta[r] * beta.get(Ie(r+1), 0) for r in beta)) -#-------------------------------------------------- +# ------------------------------------------------- # Partition tuples - parent classes -#-------------------------------------------------- +# ------------------------------------------------- + + class PartitionTuples(UniqueRepresentation, Parent): """ Class of all partition tuples. @@ -2019,7 +2027,7 @@ def _an_element_(self): sage: PartitionTuples().an_element() ([1, 1, 1, 1], [2, 1, 1], [3, 1], [4]) """ - return PartitionTuple( ([1,1,1,1],[2,1,1],[3,1],[4]) ) + return PartitionTuple(([1, 1, 1, 1], [2, 1, 1], [3, 1], [4])) class PartitionTuples_all(PartitionTuples): @@ -2112,7 +2120,7 @@ def __init__(self, level): Partition tuples of level 6 sage: TestSuite( PartitionTuples(level=4) ).run() """ - if not level in NN: + if level not in NN: raise ValueError('level must be a non-negative integer') super(PartitionTuples_level, self).__init__(category=InfiniteEnumeratedSets()) self._level=level @@ -2195,7 +2203,7 @@ def _an_element_(self): sage: PartitionTuples(level=4).an_element() ([], [1], [2], [3]) """ - return self.element_class(self, tuple([l] for l in range(self.level()) )) + return self.element_class(self, tuple([l] for l in range(self.level()))) class PartitionTuples_size(PartitionTuples): @@ -2204,7 +2212,7 @@ class PartitionTuples_size(PartitionTuples): """ def __init__(self, size): r""" - Initializes this class. + Initialize this class. EXAMPLES:: @@ -2215,7 +2223,7 @@ def __init__(self, size): sage: TestSuite( PartitionTuples(size=6) ).run() """ - if not size in NN: + if size not in NN: raise ValueError('size must be a non-negative integer') super(PartitionTuples_size, self).__init__(category=InfiniteEnumeratedSets()) self._size=size @@ -2300,7 +2308,7 @@ def _an_element_(self): sage: PartitionTuples(size=4).an_element() ([1], [1], [1], [1]) """ - return self.element_class(self, tuple([1] for l in range(self._size) )) + return self.element_class(self, tuple([1] for l in range(self._size))) class PartitionTuples_level_size(PartitionTuples): @@ -2393,7 +2401,6 @@ def __iter__(self): for cp in itertools.product(*[p[i] for i in iv]): yield self._element_constructor_(cp) - def _an_element_(self): """ Return a generic element. @@ -2403,9 +2410,10 @@ def _an_element_(self): sage: PartitionTuples(level=4,size=4).an_element() ([1], [], [], [3]) """ - mu=[[] for l in range(self._level)] + mu = [[] for l in range(self._level)] if self._size > 0: - if self._level == 1: mu=[self._size-1,1] + if self._level == 1: + mu=[self._size-1,1] else: mu[0]=[1] mu[-1]=[self._size-1] @@ -2413,9 +2421,9 @@ def _an_element_(self): def cardinality(self): r""" - Returns the number of ``level``-tuples of partitions of size ``n``. + Return the number of ``level``-tuples of partitions of size ``n``. - Wraps a pari function call. + Wraps a pari function call using :pari:`eta`. EXAMPLES:: @@ -2440,7 +2448,8 @@ def cardinality(self): These answers were checked against Gap4 (the last of which takes an awful long time for gap to compute). """ - return ZZ(gp.eval('polcoeff((1/eta(x+O(x^%s)))^%s, %s, x)'%(self.size()+1,self.level(), self.size()))) + eta = pari(f'Ser(x,x,{self.size()})').eta() + return ZZ((1 / eta**self.level()).polcoef(self.size(), pari('x'))) def __setstate__(self, state): r""" @@ -2463,7 +2472,8 @@ def __setstate__(self, state): super(PartitionTuples, self).__setstate__(state) ############################################################################### -## Regular partition tuples +# Regular partition tuples + class RegularPartitionTuples(PartitionTuples): r""" @@ -2539,6 +2549,7 @@ def _an_element_(self): elt = RegularPartitionTuples_level_size(lvl, size, self._ell).an_element() return self.element_class(self, list(elt)) + class RegularPartitionTuples_all(RegularPartitionTuples): r""" Class of `\ell`-regular partition tuples. @@ -2686,6 +2697,7 @@ def __iter__(self): for mu in RegularPartitionTuples_level_size(self._level, size, self._ell): yield self.element_class(self, list(mu)) + class RegularPartitionTuples_size(RegularPartitionTuples): r""" Class of `\ell`-regular partition tuples with a fixed size. @@ -2743,9 +2755,10 @@ def __contains__(self, mu): sage: [4, 3, 2] in RPT True """ - return ( (mu in RegularPartitions_all(self._ell) and self._size == sum(mu)) - or (RegularPartitionTuples.__contains__(self, mu) and self._size == sum(map(sum,mu))) - ) + return ((mu in RegularPartitions_all(self._ell) + and self._size == sum(mu)) + or (RegularPartitionTuples.__contains__(self, mu) + and self._size == sum(map(sum, mu)))) def __iter__(self): r""" From 1039ed05cdb3fe1e115df52221f8600614d257ee Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 17 May 2020 21:01:31 +1000 Subject: [PATCH 208/476] Adding ascii/unicode art for Temperley-Lieb/blob diagrams. --- src/doc/en/reference/references/index.rst | 2 +- src/sage/combinat/blob_algebra.py | 42 +++- src/sage/combinat/diagram_algebras.py | 230 ++++++++++++++++++++++ 3 files changed, 271 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 48c86767a6a..47427469bd9 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2774,7 +2774,7 @@ REFERENCES: Science, 447, 74–84 (2012). :doi:`10.1016/j.tcs.2011.11.011` -.. [ILZ2018] \K. Iohara, G. Gehrer, and R. Zhang. +.. [ILZ2018] \K. Iohara, G. Lehrer, and R. Zhang. *Schur-Weyl duality for certain infinite dimensional* `U_q(\mathfrak{sl}_2`-*modules*. Preprint, :arxiv:`1811.01325` (2018). diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index fb2fee244bc..cd57332e97a 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Blob Algebras @@ -26,7 +27,8 @@ from sage.functions.other import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.algebras import Algebras -from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex) +from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex, + TL_diagram_ascii_art) from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.dyck_word import DyckWords @@ -451,6 +453,42 @@ def __init__(self, k, q1, q2, q3, base_ring, prefix): CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=cat, prefix=prefix, bracket=False) + def _ascii_art_term(self, diagram): + r""" + Return an ascii art representation of ``diagram``. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B2 = algebras.Blob(2, q, r, s) + sage: x = B2.an_element() + sage: ascii_art(x) # indirect doctest + o o o o o o + 2* `-` + 3* `-` + 2* `0` + .-. .0. .-. + o o o o o o + """ + return TL_diagram_ascii_art(diagram.marked+diagram.unmarked, use_unicode=False, + blobs=diagram.marked) + + def _unicode_art_term(self, diagram): + r""" + Return a unicode art representation of ``diagram``. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B2 = algebras.Blob(2, q, r, s) + sage: x = B2.an_element() + sage: unicode_art(x) # indirect doctest + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + 2* ╰─╯ + 3* ╰─╯ + 2* ╰⚫╯ + ╭─╮ ╭⚫╮ ╭─╮ + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + """ + return TL_diagram_ascii_art(diagram.marked+diagram.unmarked, use_unicode=True, + blobs=diagram.marked) + def _latex_term(self, diagram): r""" Return a latex representation of ``diagram``. @@ -459,7 +497,7 @@ def _latex_term(self, diagram): sage: R. = ZZ[] sage: B2 = algebras.Blob(2, q, r, s) - sage: latex(B2.an_element()) + sage: latex(B2.an_element()) # indirect doctest 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index a259d23a177..23e3729be57 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Diagram and Partition Algebras @@ -3482,6 +3483,41 @@ def _element_constructor_(self, set_partition): set_partition = to_Brauer_partition(set_partition, k=self.order()) return SubPartitionAlgebra._element_constructor_(self, set_partition) + def _ascii_art_term(self, diagram): + r""" + Return an ascii art representation of ``diagram``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: TL = TemperleyLiebAlgebra(4, q, R) + sage: x = TL.an_element() + sage: ascii_art(x) # indirect doctest + o o o o o o o o + o o o o | `-` | | `-` | + 2* `-` `-` + 2* `-----` + 3* `---. | + .-. .-. .-. .-. .-. | | + o o o o o o o o o o o o + """ + return TL_diagram_ascii_art(diagram, use_unicode=False) + + def _unicode_art_term(self, diagram): + r""" + Return a unicode art representation of ``diagram``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: TL = TemperleyLiebAlgebra(4, q, R) + sage: x = TL.an_element() + sage: unicode_art(x) # indirect doctest + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + ⚬ ⚬ ⚬ ⚬ │ ╰─╯ │ │ ╰─╯ │ + 2* ╰─╯ ╰─╯ + 2* ╰─────╯ + 3* ╰───╮ │ + ╭─╮ ╭─╮ ╭─╮ ╭─╮ ╭─╮ │ │ + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + """ + return TL_diagram_ascii_art(diagram, use_unicode=True) class PlanarAlgebra(SubPartitionAlgebra, UnitDiagramMixin): r""" @@ -3705,6 +3741,200 @@ def __pow__(self, n): raise ValueError("can only take positive integer powers") return generic_power(self, n) +def TL_diagram_ascii_art(diagram, use_unicode=False, blobs=[]): + """ + Return ascii art for a Temperley-Lieb diagram ``diagram``. + + INPUT: + + - ``diagram`` -- a list of pairs of matchings of the set + `\{-1, \dotsc, -n, 1, \dotsc, n\}` + - ``use_unicode`` -- (default: ``False``): whether or not + to use unicode art instead of ascii art + - ``blobs`` -- (optional) a list of matchings with blobs on them + + EXAMPLES:: + + sage: from sage.combinat.diagram_algebras import TL_diagram_ascii_art + sage: TL = [(-15,-12), (-14,-13), (-11,15), (-10,14), (-9,-6), + ....: (-8,-7), (-5,-4), (-3,1), (-2,-1), (2,3), (4,5), + ....: (6,11), (7, 8), (9,10), (12,13)] + sage: TL_diagram_ascii_art(TL, use_unicode=False) + o o o o o o o o o o o o o o o + | `-` `-` | `-` `-` | `-` | | + | `---------` | | + | .-------` | + `---. | .-------` + | .-----. | | .-----. + .-. | .-. | .-. | | | | .-. | + o o o o o o o o o o o o o o o + sage: TL_diagram_ascii_art(TL, use_unicode=True) + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + │ ╰─╯ ╰─╯ │ ╰─╯ ╰─╯ │ ╰─╯ │ │ + │ ╰─────────╯ │ │ + │ ╭───────╯ │ + ╰───╮ │ ╭───────╯ + │ ╭─────╮ │ │ ╭─────╮ + ╭─╮ │ ╭─╮ │ ╭─╮ │ │ │ │ ╭─╮ │ + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + + sage: TL = [(-20,-9), (-19,-10), (-18,-11), (-17,-16), (-15,-12), (2,3), + ....: (-14,-13), (-8,16), (-7,7), (-6,6), (-5,1), (-4,-3), (-2,-1), + ....: (4,5), (8,15), (9,10), (11,14), (12,13), (17,20), (18,19)] + sage: TL_diagram_ascii_art(TL, use_unicode=False, blobs=[(-2,-1), (-5,1)]) + o o o o o o o o o o o o o o o o o o o o + | `-` `-` | | | `-` | `-` | | | | `-` | + | | | | `-----` | | `-----` + | | | `-------------` | + `---0---. | | .---------------` + | | | | .---------------------. + | | | | | .-----------------. | + | | | | | | .-------------. | | + | | | | | | | .-----. | | | + .0. .-. | | | | | | | | .-. | .-. | | | + o o o o o o o o o o o o o o o o o o o o + sage: TL_diagram_ascii_art(TL, use_unicode=True, blobs=[(-2,-1), (-5,1)]) + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + │ ╰─╯ ╰─╯ │ │ │ ╰─╯ │ ╰─╯ │ │ │ │ ╰─╯ │ + │ │ │ │ ╰─────╯ │ │ ╰─────╯ + │ │ │ ╰─────────────╯ │ + ╰───⚫───╮ │ │ ╭───────────────╯ + │ │ │ │ ╭─────────────────────╮ + │ │ │ │ │ ╭─────────────────╮ │ + │ │ │ │ │ │ ╭─────────────╮ │ │ + │ │ │ │ │ │ │ ╭─────╮ │ │ │ + ╭⚫╮ ╭─╮ │ │ │ │ │ │ │ │ ╭─╮ │ ╭─╮ │ │ │ + ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ + """ + def insert_pairing(cur, intervals): + """ + Helper function to insert a possibly nested interval + and push the others up, assuming inserting points from + right-to-left. + """ + for level in intervals: + for j, I in enumerate(level): + # Singleton intervals are vertical lines, + # so we don't need to worry about them + if len(I) > 1 and I[0] < cur[0]: + cur, level[j] = level[j], cur + level.append([cur[0]]) + level.append([cur[1]]) + break + else: + level.append(cur) + return # We have stopped + else: + intervals.append([cur]) + # Build a set of intervals that defines where to draw the diagram + intervals = [[]] + propogating = [] + vertical = [] + top_intervals = [[]] + num_left = 0 + num_right = 0 + def key_func(P): + if P[1] < 0: # cap + return (0, P[0], P[1]) + elif P[0] > 0: # cup + return (3, -P[1], -P[0]) + else: + bot, top = -P[0], P[1] + if top < bot: # left moving + return (1, top, bot) + elif top > bot: # right moving + return (2, -bot, -top) + else: # vertical line + return (1, top, bot) + diagram = sorted(diagram, key=key_func) + # Since diagram is sorted in lex order, we will first do the matchings + # from right-to-left on the bottom, then the propogating lines, and + # then the matchings on the top from right-to-left. + # Note that we need the top to go from right-to-left so the + # insert_pairing() function's assumptions are satisfied. + for P in diagram: + if P[1] < 0: # Bottom matching + insert_pairing([-P[1], -P[0], False, False], intervals) + elif P[0] > 0: # Top matching + insert_pairing([P[0], P[1], True, True], top_intervals) + else: # Propogating line + if -P[0] == P[1]: + vertical.append(P[1]) + else: + if -P[0] < P[1]: + num_right += 1 + else: + num_left += 1 + propogating.append(P) + + # Now piece together the intervals together + total_prop = max(num_left, num_right) + prop_intervals = [[] for _ in range(total_prop)] + count_left = 0 + # Recall that the left-moving propogating lines come before the right-moving + for i, P in enumerate(propogating): + bot, top = P + bot = -bot # This makes it equal to its x-coordinate + for level in intervals: + level.append([bot]) + for level in top_intervals: + level.append([top]) + left_moving = count_left < num_left + if not left_moving: + i -= num_left + else: + count_left += 1 + for j in range(i): + prop_intervals[j].append([bot]) + for j in range(i+1,total_prop): + prop_intervals[j].append([top]) + if not left_moving: + top, bot = bot, top + prop_intervals[i].append([top, bot, left_moving, not left_moving]) + intervals += prop_intervals + intervals += reversed(top_intervals) + for level in intervals: + level.extend([i] for i in vertical) + + n = max(max(P) for P in diagram) + + # Finally, convert to a picture + if use_unicode: + from sage.typeset.unicode_art import UnicodeArt + d = ["╭", "╮", "╰", "╯", "─", "│"] + #db = ["┏", "┓", "┗", "┛", "━", "┃"] + blob = '⚫' + ret = [" ⚬" * n] + char_art = UnicodeArt + else: + from sage.typeset.ascii_art import AsciiArt + d = [".", ".", "`", "`", "-", "|"] + #db = [".", ".", "`", "`", "=", "|"] + blob = '0' + ret = [" o" * n] + char_art = AsciiArt + def signed(val, pos): + return val if pos else -val + for level in reversed(intervals): + cur = "" + for I in sorted(level): + cur += ' '*(2*I[0]-1 - len(cur)) + if len(I) == 1: + cur += d[5] + ' ' + else: + cur += d[2] if I[2] else d[0] + if tuple(sorted([signed(I[0], I[2]), signed(I[1], I[3])])) in blobs: + cur += d[4] * (I[1]-I[0]-1) + cur += blob + cur += d[4] * (I[1]-I[0]-1) + else: + cur += d[4] * (2*(I[1]-I[0])-1) + cur += d[3] if I[3] else d[1] + ret.append(cur) + # Note that the top row and bottom row will be the same + ret.append(ret[0]) + return char_art(ret, baseline=len(ret)//2) + def diagram_latex(diagram, fill=False, edge_options=None, edge_additions=None): r""" Return latex code for the diagram ``diagram`` using tikz. From 034d71ace4312b495de3ba434566f75bbe621b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Sun, 17 May 2020 16:22:22 +0200 Subject: [PATCH 209/476] 29700:catching also ValueError --- src/sage/matrix/matrix2.pyx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index c5146cc87c0..649e6d70e10 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -13679,13 +13679,20 @@ cdef class Matrix(Matrix1): [0.750000000000000 0.800000000000000 0.833333333333333] [0.857142857142857 0.875000000000000 0.888888888888889] [0.900000000000000 0.909090909090909 0.916666666666667] + + We check that :trac:`29700` is fixed:: + + sage: M = matrix(3,[1,1,1,1,0,0,0,1,0]) + sage: A,B = M.diagonalization(QQbar) + sage: _ = A.n() + """ if prec is None: prec = digits_to_bits(digits) try: return self.change_ring(sage.rings.real_mpfr.RealField(prec)) - except TypeError: + except (TypeError, ValueError): # try to return a complex result return self.change_ring(sage.rings.complex_field.ComplexField(prec)) From b7fdccb1f2a0022e483d7e23f7f0dedca9a94ef7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 18 May 2020 11:22:37 +1000 Subject: [PATCH 210/476] A few other micro-optimizations. --- .../rings/polynomial/multi_polynomial.pyx | 2 +- .../polynomial/multi_polynomial_element.py | 34 ++++++++++--------- .../multi_polynomial_libsingular.pyx | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 5005386cf4e..25de569ee2f 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -357,7 +357,7 @@ cdef class MPolynomial(CommutativeRingElement): x = [etb.var(v) for v in my_vars] n = len(x) - expr = etb.constant(self.base_ring()(0)) + expr = etb.constant(self.base_ring().zero()) for (m, c) in self.dict().iteritems(): monom = prod([ x[i]**m[i] for i in range(n) if m[i] != 0], etb.constant(c)) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index ea51eebf0e1..3a949c31c82 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -394,7 +394,7 @@ def __init__(self, parent, x): True """ if not isinstance(x, polydict.PolyDict): - x = polydict.PolyDict(x, parent.base_ring()(0), remove_zero=True) + x = polydict.PolyDict(x, parent.base_ring().zero(), remove_zero=True) MPolynomial_element.__init__(self, parent, x) def _new_constant_poly(self, x, P): @@ -822,7 +822,7 @@ def __getitem__(self, x): try: return self.element()[x] except KeyError: - return self.parent().base_ring()(0) + return self.parent().base_ring().zero() def __iter__(self): """ @@ -851,7 +851,7 @@ def __iter__(self): """ elt = self.element() ring = self.parent() - one = ring.base_ring()(1) + one = ring.base_ring().one() for exp in self._exponents: yield (elt[exp], MPolynomial_polydict(ring, polydict.PolyDict({exp:one}, @@ -1252,7 +1252,7 @@ def monomials(self): True """ ring = self.parent() - one = ring.base_ring()(1) + one = ring.base_ring().one() return [MPolynomial_polydict(ring, polydict.PolyDict({m:one}, force_int_exponents=False, force_etuples=False)) for m in self._exponents] @@ -1275,7 +1275,7 @@ def constant_coefficient(self): try: return d[polydict.ETuple({},self.parent().ngens())] except KeyError: - return self.parent().base_ring()(0) + return self.parent().base_ring().zero() def is_univariate(self): """ @@ -1503,7 +1503,7 @@ def lm(self): return self R = self.parent() f = self._MPolynomial_element__element.lcmt( R.term_order().greater_tuple ) - one = R.base_ring()(1) + one = R.base_ring().one() self.__lm = MPolynomial_polydict(R,polydict.PolyDict({f:one},zero=R.base_ring().zero(),force_int_exponents=False, force_etuples=False)) return self.__lm @@ -1669,7 +1669,8 @@ def _derivative(self, var=None): if var is None: raise ValueError("must specify which variable to differentiate with respect to") - gens = list(self.parent().gens()) + P = self.parent() + gens = list(P.gens()) # check if var is one of the generators try: @@ -1678,8 +1679,8 @@ def _derivative(self, var=None): # var is not a generator; do term-by-term differentiation recursively # var may be, for example, a generator of the base ring d = dict([(e, x._derivative(var)) for (e, x) in iteritems(self.dict())]) - d = polydict.PolyDict(d, self.parent().base_ring()(0), remove_zero=True) - return MPolynomial_polydict(self.parent(), d) + d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) + return MPolynomial_polydict(P, d) # differentiate w.r.t. indicated variable d = {} @@ -1687,8 +1688,8 @@ def _derivative(self, var=None): for (exp, coeff) in iteritems(self.dict()): if exp[index] > 0: d[exp.esub(v)] = coeff * exp[index] - d = polydict.PolyDict(d, self.parent().base_ring()(0), remove_zero=True) - return MPolynomial_polydict(self.parent(), d) + d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) + return MPolynomial_polydict(P, d) def integral(self, var=None): r""" @@ -1740,7 +1741,8 @@ def integral(self, var=None): raise ValueError("must specify which variable to integrate " "with respect to") - gens = list(self.parent().gens()) + P = self.parent() + gens = list(P.gens()) # check if var is one of the generators try: @@ -1750,17 +1752,17 @@ def integral(self, var=None): # var may be, for example, a generator of the base ring d = dict([(e, x.integral(var)) for (e, x) in iteritems(self.dict())]) - d = polydict.PolyDict(d, self.parent().base_ring()(0), + d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) - return MPolynomial_polydict(self.parent(), d) + return MPolynomial_polydict(P, d) # integrate w.r.t. indicated variable d = {} v = polydict.ETuple({index:1}, len(gens)) for (exp, coeff) in iteritems(self.dict()): d[exp.eadd(v)] = coeff / (1+exp[index]) - d = polydict.PolyDict(d, self.parent().base_ring()(0), remove_zero=True) - return MPolynomial_polydict(self.parent(), d) + d = polydict.PolyDict(d, P.base_ring().zero(), remove_zero=True) + return MPolynomial_polydict(P, d) def factor(self, proof=None): r""" diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 1bae398726d..aa0b7452da0 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2121,7 +2121,7 @@ cdef class MPolynomial_libsingular(MPolynomial): coerced_x = [parent.coerce(e) for e in x] except TypeError: # give up, evaluate functional - y = parent.base_ring()(0) + y = parent.base_ring().zero() for (m,c) in self.dict().iteritems(): y += c*mul([ x[i]**m[i] for i in m.nonzero_positions()]) return y From ee73868072306af56350a288d1b2fee12457e26c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 18 May 2020 11:25:42 +1000 Subject: [PATCH 211/476] Some last minute details to clean the generic MPoly file. --- .../polynomial/multi_polynomial_element.py | 101 ++++++++---------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 3a949c31c82..688d33158d1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -761,27 +761,51 @@ def dict(self): """ return self.element().dict() - #def __iter__(self): - # """ - # Facilitates iterating over the monomials of self, - # returning tuples of the form (coeff, mon) for each - # non-zero monomial. - # - # EXAMPLES:: - - # sage: R = ZZ['t'] - # sage: P. = PolynomialRing(R,3) - # sage: f = 3*x^3*y + 16*x + 7 - # sage: [(c,m) for c,m in f] - # [(3, x^3*y), (16, x), (7, 1)] - # sage: f = P.random_element(10,10) - # sage: sum(c*m for c,m in f) == f - # True - # """ - # exps = self.exponents() - # parent = self.parent() - # for exp in exps: - # yield self.element()[exp], MPolynomial_polydict(parent, {exp: 1}) + def __iter__(self): + """ + Iterate over ``self`` respecting the term order. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQbar, order='lex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x^4*y*z^3), (1, x^2*z), (1, x*y^5*z^2)] + + :: + + sage: R. = PolynomialRing(QQbar, order='deglex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x^4*y*z^3), (1, x*y^5*z^2), (1, x^2*z)] + + :: + + sage: R. = PolynomialRing(QQbar, order='degrevlex') + sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) + sage: list(f) + [(1, x*y^5*z^2), (1, x^4*y*z^3), (1, x^2*z)] + + :: + + sage: R = ZZ['t'] + sage: P. = PolynomialRing(R,3) + sage: f = 3*x^3*y + 16*x + 7 + sage: [(c,m) for c,m in f] + [(3, x^3*y), (16, x), (7, 1)] + sage: f = P.random_element(10,10) + sage: sum(c*m for c,m in f) == f + True + """ + elt = self.element() + ring = self.parent() + one = ring.base_ring().one() + for exp in self._exponents: + yield (elt[exp], + MPolynomial_polydict(ring, polydict.PolyDict({exp:one}, + force_int_exponents=False, + force_etuples=False)) + ) def __getitem__(self, x): """ @@ -824,41 +848,6 @@ def __getitem__(self, x): except KeyError: return self.parent().base_ring().zero() - def __iter__(self): - """ - Iterate over ``self`` respecting the term order. - - EXAMPLES:: - - sage: R. = PolynomialRing(QQbar, order='lex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) - [(1, x^4*y*z^3), (1, x^2*z), (1, x*y^5*z^2)] - - :: - - sage: R. = PolynomialRing(QQbar, order='deglex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) - [(1, x^4*y*z^3), (1, x*y^5*z^2), (1, x^2*z)] - - :: - - sage: R. = PolynomialRing(QQbar, order='degrevlex') - sage: f = (x^1*y^5*z^2 + x^2*z + x^4*y^1*z^3) - sage: list(f) - [(1, x*y^5*z^2), (1, x^4*y*z^3), (1, x^2*z)] - """ - elt = self.element() - ring = self.parent() - one = ring.base_ring().one() - for exp in self._exponents: - yield (elt[exp], - MPolynomial_polydict(ring, polydict.PolyDict({exp:one}, - force_int_exponents=False, - force_etuples=False)) - ) - def iterator_exp_coeff(self, as_ETuples=True): """ Iterate over ``self`` as pairs of ((E)Tuple, coefficient). From 66bf321e35062aeac0364aab969da7bd09471eee Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 20:28:27 -0700 Subject: [PATCH 212/476] 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 213/476] 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 214/476] 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 215/476] 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 216/476] 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 217/476] 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 218/476] 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 7dd76f64ed82e803c8e17263e79f6a6840843d20 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 19 May 2020 10:31:37 +1000 Subject: [PATCH 219/476] Added an r""" to TL_diagram_ascii_art(). --- 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 23e3729be57..2bb98b120e8 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -3742,7 +3742,7 @@ def __pow__(self, n): return generic_power(self, n) def TL_diagram_ascii_art(diagram, use_unicode=False, blobs=[]): - """ + r""" Return ascii art for a Temperley-Lieb diagram ``diagram``. INPUT: From 387c0bd94ed25057df5003e6ec7ae38018191524 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 19 May 2020 10:38:15 +0100 Subject: [PATCH 220/476] 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 221/476] 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 e5e91e7a8d8fbabb93ed2ff7278c7eefa19da44c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 20 May 2020 12:41:29 +1000 Subject: [PATCH 222/476] Better unicode object for the blob. --- src/sage/combinat/blob_algebra.py | 4 ++-- src/sage/combinat/diagram_algebras.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index cd57332e97a..8d719b29103 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -482,8 +482,8 @@ def _unicode_art_term(self, diagram): sage: x = B2.an_element() sage: unicode_art(x) # indirect doctest ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ - 2* ╰─╯ + 3* ╰─╯ + 2* ╰⚫╯ - ╭─╮ ╭⚫╮ ╭─╮ + 2* ╰─╯ + 3* ╰─╯ + 2* ╰●╯ + ╭─╮ ╭●╮ ╭─╮ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ """ return TL_diagram_ascii_art(diagram.marked+diagram.unmarked, use_unicode=True, diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 2bb98b120e8..042aad3e1c4 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -3798,12 +3798,12 @@ def TL_diagram_ascii_art(diagram, use_unicode=False, blobs=[]): │ ╰─╯ ╰─╯ │ │ │ ╰─╯ │ ╰─╯ │ │ │ │ ╰─╯ │ │ │ │ │ ╰─────╯ │ │ ╰─────╯ │ │ │ ╰─────────────╯ │ - ╰───⚫───╮ │ │ ╭───────────────╯ + ╰───●───╮ │ │ ╭───────────────╯ │ │ │ │ ╭─────────────────────╮ │ │ │ │ │ ╭─────────────────╮ │ │ │ │ │ │ │ ╭─────────────╮ │ │ │ │ │ │ │ │ │ ╭─────╮ │ │ │ - ╭⚫╮ ╭─╮ │ │ │ │ │ │ │ │ ╭─╮ │ ╭─╮ │ │ │ + ╭●╮ ╭─╮ │ │ │ │ │ │ │ │ ╭─╮ │ ╭─╮ │ │ │ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ """ def insert_pairing(cur, intervals): @@ -3903,7 +3903,7 @@ def key_func(P): from sage.typeset.unicode_art import UnicodeArt d = ["╭", "╮", "╰", "╯", "─", "│"] #db = ["┏", "┓", "┗", "┛", "━", "┃"] - blob = '⚫' + blob = '●' ret = [" ⚬" * n] char_art = UnicodeArt else: From 52e465147710e82874e3f5906f3e804e7959ce77 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 20 May 2020 15:19:27 +1000 Subject: [PATCH 223/476] Allowing a larger number of things to convert into the fraction field. --- src/sage/rings/fraction_field.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 1c4285d039f..15328d7bbe8 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -81,6 +81,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.richcmp import richcmp from sage.structure.parent import Parent +from sage.structure.element import parent from sage.structure.coerce import py_scalar_to_element from sage.structure.coerce_maps import CallableConvertMap, DefaultConvertMap_unique from sage.categories.basic import QuotientFields, Rings @@ -608,8 +609,21 @@ def _element_constructor_(self, x, y=None, coerce=True): sage: S. = ZZ[] sage: S.fraction_field()(s/(s+1), (t-1)/(t+2)) (s^2 + 2*s)/(s^2 - 1) + + Check that :trac:`29713` is fixed:: + + sage: F = FractionField(QQ['a']) + sage: a = F.gen() + sage: R = PolynomialRing(F, 'x') + sage: FF = FractionField(R) + sage: elt = F(-1/2/(a^2+a)) + sage: x = FF(elt) + sage: F(x) + -1/2/(a^2 + a) """ if y is None: + if parent(x) is self: + return x ring_one = self.ring().one() try: return self._element_class(self, x, ring_one, coerce=coerce) @@ -618,6 +632,9 @@ def _element_constructor_(self, x, y=None, coerce=True): y = self._element_class(self, ring_one, ring_one, coerce=False, reduce=False) else: + if parent(x) is self: + y = self(y) + x, y = x.numerator() * y.denominator(), y.numerator() * x.denominator() try: return self._element_class(self, x, y, coerce=coerce) except (TypeError, ValueError): @@ -660,12 +677,12 @@ def resolve_fractions(x, y): except (AttributeError, TypeError, ValueError): pass try: - P = yd.parent() + P = parent(yd) return (P(xn) * yd, yn * P(xd)) except (AttributeError, TypeError, ValueError): pass try: - P = xd.parent() + P = parent(xd) return (xn * P(yd), P(yn) * xd) except (AttributeError, TypeError, ValueError): pass @@ -682,7 +699,11 @@ def resolve_fractions(x, y): return self._element_class(self, x, y, coerce=coerce) except TypeError: if not x != x0: - raise + # Make one last attempt to convert x into ``self`` + x = self(x) + y *= x.denominator() + x = x.numerator() + return self._element_class(self, x, y, coerce=coerce) def construction(self): """ From f1bb41e3b2c6fd52993f18363c1e9768bdfdf007 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Wed, 20 May 2020 09:23:39 +0200 Subject: [PATCH 224/476] 29716 initial version --- src/doc/en/reference/algebras/index.rst | 1 + src/doc/en/reference/references/index.rst | 12 + src/sage/algebras/splitting_algebra.py | 816 ++++++++++++++++++++++ 3 files changed, 829 insertions(+) create mode 100644 src/sage/algebras/splitting_algebra.py diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 133cfb7371c..2a7c43950da 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -88,6 +88,7 @@ Various associative algebras sage/algebras/cellular_basis sage/algebras/commutative_dga sage/algebras/q_system + sage/algebras/splitting_algebra Non-associative algebras ------------------------ diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 91aeb96553b..8c5c36ff174 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1964,6 +1964,9 @@ REFERENCES: Version 1.3". 2013. http://www.wolfgang-ehrhardt.de/specialfunctions.pdf. +.. [EL2002] Ekedahl, Torsten & Laksov, Dan. (2002). *Splitting algebras, Symmetric functions and + Galois Theory*. J. Algebra Appl. 4, :doi:`10.1142/S0219498805001034` + .. [EM2001] Pavel Etingof and Xiaoguang Ma. *Lecture notes on Cherednik algebras*. http://www-math.mit.edu/~etingof/73509.pdf :arxiv:`1001.0432`. @@ -3378,6 +3381,9 @@ REFERENCES: Mémoire de maîtrise en Mathématiques, Montréal, UQAM, 2008, 109 pages. +.. [Lak2010] Dan Laksov. *Splitting algebras and Gysin homomorphisms*. + Journal of Commutative Algebra, Volume 2, Number 3, Fall 2010 + .. [Lam1996] \T. K. Lam. *B and D analogues of stable Schubert polynomials and related insertion algorithms*. PhD Thesis, MIT, 1996. @@ -3661,6 +3667,9 @@ REFERENCES: groups*. Australian Mathematical Society Lecture Series, 2009. +.. [LT2012] Dan Laksov, Anders Thorup. *Splitting algebras and Schubert calculus*, + Indiana Univ. Math. J. 61 (2012), 1253-1312 :doi:`10.1512/iumj.2012.61.4791` + .. [DeLuca2006] \A. De Luca, *Pseudopalindrome closure operators in free monoids*, Theoret. Comput. Sci. 362 (2006) 282--300. @@ -5158,6 +5167,9 @@ REFERENCES: height on elliptic curves over number fields, Math. Comp. 79 (2010), pages 2431-2449. +.. [Tho2011] Anders Thorup. *ON THE INVARIANTS OF THE SPLITTING ALGEBRA*, + 2011, :arxiv:`1105.4478` + .. [TIDES] \A. Abad, R. Barrio, F. Blesa, M. Rodriguez. TIDES tutorial: Integrating ODEs by using the Taylor Series Method (http://www.unizar.es/acz/05Publicaciones/Monografias/MonografiasPublicadas/Monografia36/IndMonogr36.htm) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py new file mode 100644 index 00000000000..020cc3145d4 --- /dev/null +++ b/src/sage/algebras/splitting_algebra.py @@ -0,0 +1,816 @@ +# -*- coding: utf-8 -*- +r""" +Splitting Algebras + +*Splitting algebras* have been considered by Dan Laksov, Anders Thorup, Torsten Ekedahl and others (see references below) in order +to study intersection theory of Grassmann and other flag schemes. Similarily as *splitting fields* they can be considered as +extensions of rings containing all the roots of a given monic polynomial over that ring under the assumption that its Galois +group is the symmetric group of order equal to the polynomial's degree. + +Thus they can be used as a tool to express elements of a ring generated by `n` indeterminates in terms of symmetric functions +in these indeterminates. + +This realization of splitting algebras follows the approach of a recursive quotient ring construction splitting off some linear +factor of the polynomial in each recursive step. Accordingly it is inherited from :class:`PolynomialQuotientRing_domain`. + +AUTHORS: + +- Sebastian Oehms April 2020: initial version +""" + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +############################################################################## + + + + +#################################################################################################### +#################################################################################################### + +from warnings import warn + +from sage.structure.element import get_coercion_model +from sage.misc.misc import verbose +from sage.misc.cachefunc import cached_method +from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_domain, PolynomialQuotientRing_generic +from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement + + + + + +# ------------------------------------------------------------------------------------------------------------------ +# Element class for the splitting algebra +# -------------------------------------------------------------------------------------------------------- +class SplittingAlgebraElement(PolynomialQuotientRingElement): + r""" + Element class for :class:`SplittingAlgebra` + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: from sage.misc.functional import cyclotomic_polynomial + sage: cp6 = cyclotomic_polynomial(6) + sage: CR6. = SplittingAlgebra(cp6) + sage: type(e6) + + + sage: type(CR6(5)) + + """ + + def __invert__(self): + r""" + overloads inherited method in order to support inversion of special elements attached + to the construction of the parent and which are recorded in the list + ``self.parent()._invertible_elements``. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: from sage.misc.functional import cyclotomic_polynomial + sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) + sage: ~e3 + -e3 - 1 + sage: ~(e3 + 5) + Traceback (most recent call last): + ... + NotImplementedError: The base ring (=Integer Ring) is not a field + """ + inv_elements = self.parent()._invertible_elements + if self in inv_elements.keys(): + return inv_elements[self] + + return super(SplittingAlgebraElement, self).__invert__() + + + def is_unit(self): + r""" + Return ``True`` if ``self`` is invertible. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: from sage.misc.functional import cyclotomic_polynomial + sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) + sage: e3.is_unit() + True + """ + inv_elements = self.parent()._invertible_elements + if self in inv_elements.keys(): + return True + + return super(SplittingAlgebraElement, self).is_unit() + + def dict(self): + r""" + Return the dictionary of ``self`` according to its lift to the cover. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: from sage.misc.functional import cyclotomic_polynomial + sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) + sage: (e3 + 42).dict() + {0: 42, 1: 1} + """ + return self.lift().dict() + + + +# ------------------------------------------------------------------------------------------------------------------ +# Parent class of the splitting algebra +# -------------------------------------------------------------------------------------------------------- +class SplittingAlgebra(PolynomialQuotientRing_domain): + r""" + For a given monic polynomial `p(t)` of degree `n` over a commutative ring `R`, the + splitting algebra is the universal `R`-algebra in which `p(t)` has `n` roots, or, + more precisely, over which `p(t)` factors, + + .. MATH:: + + p(t) = (t - \xi_1 ) \cdots (t - \xi_n). + + This class creates an algebra as extension over the base ring of a given polynomial + `p` such that `p` splits into linear factors over that extension. It is assumed + (and not checked in general) that the Galois group of `p` is the symmetric Group + `S(n)`. The construction is recursive (following [LT2012]_, 1.3). + + INPUT: + + - ``monic_polynomial`` -- the monic polynomial which should be split + - ``names`` -- names for the indeterminates to be adjoined to the base ring of + ``monic_polynomial`` + - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) + to suppress a warning which will be thrown whenever it cannot be checked that + the Galois group of ``monic_polynomial`` is maximal + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: Lc. = LaurentPolynomialRing(ZZ) + sage: PabLc. = Lc[]; t = polygen(PabLc) + sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t -w) + doctest:...: UserWarning: Asuming x^3 - u*x^2 + v*x - w to have maximal + Galois group! + + sage: roots = S.splitting_roots(); roots + [x, y, -y - x + u] + sage: all(t^3 -u*t^2 +v*t -w == 0 for t in roots) + True + sage: ~x + ((-w^-1)*x)*y + (-w^-1)*x^2 + ((w^-1)*u)*x + sage: ~_ == x + True + sage: ~y + (w^-1)*x^2 + ((-w^-1)*u)*x + (w^-1)*v + sage: zi = ((w^-1)*x)*y; ~zi + -y - x + u + + sage: cp3 = cyclotomic_polynomial(3).change_ring(GF(5)) + sage: CR3. = SplittingAlgebra(cp3) + sage: CR3.is_field() + True + sage: CR3.cardinality() + 25 + sage: F. = cp3.splitting_field() + sage: F.cardinality() + 25 + sage: E3 = cp3.change_ring(F).roots()[0][0]; E3 + 3*a + 3 + sage: f = CR3.hom([E3]); f + Ring morphism: + From: Splitting Algebra of x^2 + x + 1 + with roots [e3, 4*e3 + 4] + over Finite Field of size 5 + To: Finite Field in a of size 5^2 + Defn: e3 |--> 3*a + 3 + + REFERENCES: + + - [EL2002]_ + - [Lak2010]_ + - [Tho2011]_ + - [LT2012]_ + """ + + Element = SplittingAlgebraElement + + def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): + r""" + Python constructor. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: Lw. = LaurentPolynomialRing(ZZ) + sage: PuvLw. = Lw[]; t = polygen(PuvLw) + sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t - w) + sage: TestSuite(S).run() + """ + + # --------------------------------------------------------------------------------- + # checking input parameters + # --------------------------------------------------------------------------------- + + base_ring = monic_polynomial.base_ring() + if not monic_polynomial.is_monic(): + raise ValueError('Given polynomial must be monic') + deg = monic_polynomial.degree() + + from sage.structure.category_object import normalize_names + self._root_names = normalize_names(deg-1, names) + root_names = list(self._root_names) + verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" %(base_ring, monic_polynomial, iterate, warning)) + + self._defining_polynomial = monic_polynomial + self._iterate = iterate + + try: + if base_ring.is_integral_domain() == False: + raise TypeError( "base_ring must be an integral domain" ) + except NotImplementedError: + from sage.rings.ring import Ring + if isinstance(base_ring, Ring) == False: + raise TypeError( "base_ring must be an instance of ring" ) + if warning == True: + warn('Assuming %s to be an integral domain!' %(base_ring)) + + + if deg < 1 : + raise ValueError( "the degree of the polynomial must positive" ) + + self._splitting_roots = [] + self._coefficients_list = [] + self._invertible_elements = {} + + if isinstance(base_ring, SplittingAlgebra): + self._invertible_elements = base_ring._invertible_elements + + # ------------------------------------------------------------------------------------ + # taking next root_name + # ------------------------------------------------------------------------------------ + root_name = root_names[0] + p = monic_polynomial.change_variable_name(root_name) + P = p.parent() + + self._set_modulus_irreducible_ = False + try: + if p.is_irreducible() == False: + raise ValueError( "monic_polynomial must be irreducible" ) + except (NotImplementedError, AttributeError): + # assuming this has been checked mathematically before + self._set_modulus_irreducible_ = True + if warning == True: + warn('Asuming %s to have maximal Galois group!' %(monic_polynomial)) + warning = False # one warning must be enough + + verbose("P %s defined:" %(P)) + + if deg > 2 and iterate: + # ------------------------------------------------------------------------------------ + # successive solution via recursion (on base_ring_step) + # ------------------------------------------------------------------------------------ + base_ring_step = SplittingAlgebra(monic_polynomial, tuple(root_names), iterate=False, warning=False) + first_root = base_ring_step.gen() + + verbose("base_ring_step %s defined:" %(base_ring_step)) + + # ------------------------------------------------------------------------------------ + # splitting first root off + # ------------------------------------------------------------------------------------ + from copy import copy + root_names_reduces = copy(root_names) + root_names_reduces.remove(root_name) + + P = base_ring_step[root_names_reduces[0]] + p = P(monic_polynomial.dict()) + q, r = p.quo_rem( (P.gen()-first_root) ) + + verbose("Invoking recursion with: %s" %(q)) + + SplittingAlgebra.__init__(self, q, root_names_reduces, warning=False) + + splitting_roots = base_ring_step._splitting_roots + self._splitting_roots + coefficients_list = base_ring_step._coefficients_list + self._coefficients_list + + verbose("Adding roots: %s" %(splitting_roots)) + + self._splitting_roots = splitting_roots + self._coefficients_list = coefficients_list + else: + PolynomialQuotientRing_domain.__init__(self, P, p, root_name) + + first_root = self.gen() + self._splitting_roots.append(first_root) + self._coefficients_list = [monic_polynomial.coefficients(sparse=False)] + + if iterate == False: + verbose("pre ring defined splitting_roots: %s" %(self._splitting_roots)) + return + + verbose("final ring defined splitting_roots: %s" %(self._splitting_roots)) + + if deg == 2 : + coefficients = monic_polynomial.coefficients(sparse=False) + lin_coeff = coefficients[1] + self._splitting_roots.append(-lin_coeff - first_root) + + self._root_names = names + self._splitting_roots = [self(root) for root in self._splitting_roots] + verbose("splitting_roots: %s embedded" %(self._splitting_roots)) + + + # ------------------------------------------------------------------------------------------- + # try to calculate inverses of the roots. This is possible if the original polynomial + # has an invertible constant term. For example let cf = [-w, v,-u, 1] that is + # p = h^3 -u*h^2 + v*h -w, than u = x + y + z, v = x*y + x*z + y*z, w = x*y*z. If + # w is invertible then 1/x = (v -(u-x)*x)/w, 1/y = (v -(u-y)*y)/w, 1/z = (v -(u-z)*z)/w + # ------------------------------------------------------------------------------------------- + # first find the polynomial with invertible constant coefficient + # ------------------------------------------------------------------------------------------- + cf0_inv = None + for cf in self._coefficients_list: + cf0 = cf[0] + try: + cf0_inv = ~(cf[0]) + cf0_inv = self(cf0_inv) + verbose("invertible coefficient: %s found" %(cf0_inv)) + break + except NotImplementedError: + verbose("constant coefficient: %s not invertibe" %(cf0)) + + + # ---------------------------------------------------------------------------------- + # assuming that cf splits into linear factors over self and the _splitting_roots + # are its roots we can calculate inverses + # ---------------------------------------------------------------------------------- + if cf0_inv != None: + deg_cf = len(cf)-1 + pf = P(cf) + for root in self._splitting_roots: + check=self(pf) + if not check.is_zero(): + continue + root_inv = self.one() + for pos in range(deg_cf-1 ): + root_inv = (-1 )**(pos+1 )*cf[deg_cf-pos-1 ] - root_inv*root + verbose("inverse %s of root %s" %(root_inv, root)) + root_inv = (-1 )**(deg_cf)*cf0_inv*root_inv + self._invertible_elements.update({root:root_inv}) + verbose("adding inverse %s of root %s" %(root_inv, root)) + invert_items = [(k,v) for k, v in self._invertible_elements.items()] + for k, v in invert_items: + self._invertible_elements.update({v:k}) + return + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + def __reduce__(self): + r""" + Used in pickling. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: S = SplittingAlgebra(x^4 -t*x^3 - u*x^2 - v*x + w, ('X', 'Y', 'Z')) + sage: S.__reduce__() + (, + (x^4 - t*x^3 - u*x^2 - v*x + w, ('X', 'Y', 'Z'), True, False)) + sage: S.base_ring().__reduce__() + (, + (Y^3 + (X - t)*Y^2 + (X^2 - t*X - u)*Y + X^3 - t*X^2 - u*X - v, + ('Y', 'Z'), + False, + False)) + + TESTS:: + + TestSuite(SplAlg).run() + """ + defining_polynomial = self.defining_polynomial() + definig_coefficients = self._coefficients_list[0] + if defining_polynomial.coefficients(sparse=False) != definig_coefficients: + # case of factorization algebra (intermediate construction step) + par_pol = self.cover_ring() + defining_polynomial = par_pol(definig_coefficients) + return self.__class__, (defining_polynomial, self._root_names, self._iterate, False) + + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = PolynomialRing(ZZ) + sage: t = polygen(L) + sage: Spl. = SplittingAlgebra(t^3 - (u^2-v)*t^2 + (v+u)*t - 1) + sage: Spl._repr_() + 'Splitting Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 + with roots [S, T, -T - S + u^2 - v] + over Multivariate Polynomial Ring in u, v over Integer Ring' + sage: Spl.base_ring() # indirect doctest + Factorization Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 + with roots [S] over Multivariate Polynomial Ring in u, v over Integer Ring + """ + if self.is_completely_split(): + return 'Splitting Algebra of %s with roots %s over %s' %(self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) + else: + return 'Factorization Algebra of %s with roots %s over %s' %(self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) + + def _first_ngens(self, n): + r""" + Used by the preparser for ``R. = ...``. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = PolynomialRing(ZZ) + sage: t = polygen(L) + sage: S. = SplittingAlgebra(t^3 - (u^2-v)*t^2 + (v+u)*t - 1) # indirect doctest + sage: X.parent() + Splitting Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 with roots [X, Y, -Y - X + u^2 - v] + over Multivariate Polynomial Ring in u, v over Integer Ring + """ + return self.gens_recursive()[:n] + + def _element_constructor_(self, x): + r""" + Make sure ``x`` is a valid member of ``self``, and return the constructed element. + + TESTS:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: S. = SplittingAlgebra(x^3 - u*x^2 + v*x - w) + sage: TestSuite(S).run() # indirect doctest + """ + if isinstance(x, SplittingAlgebraElement): + # coercion from covering fixes pickling problems + return self(x.lift()) + return super(SplittingAlgebra, self)._element_constructor_(x) + + + + def hom(self, im_gens, codomain=None, check=True, base_map=None): + r""" + This version keeps track with the special recursive structure + of :class:`SplittingAlgebra` + + Type ``Ring.hom?`` to see the general documentation of this method. + Here you see just special examples for the current class. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) + sage: P. = PolynomialRing(ZZ) + sage: F = FractionField(P) + sage: im_gens = [F(g) for g in [y, x, x + y + z, x*y+x*z+y*z, x*y*z]] + sage: f = S.hom(im_gens) + sage: f(u), f(v), f(w) + (x + y + z, x*y + x*z + y*z, x*y*z) + sage: roots = S.splitting_roots(); roots + [X, Y, -Y - X + u] + sage: [f(r) for r in roots] + [x, y, z] + """ + + base_ring = self.base_ring() + + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + + all_gens = self.gens_dict_recursive() + if len(im_gens) != len(all_gens): + return super(SplittingAlgebra, self).hom(im_gens, codomain=codomain, check=check, base_map=base_map) + + num_gens = len(self.gens()) + im_gens_start = [img for img in im_gens if im_gens.index(img) < num_gens] + im_gens_end = [img for img in im_gens if im_gens.index(img) >= num_gens] + + if len(im_gens_end) == 0 : + return super(SplittingAlgebra, self).hom(im_gens, codomain=codomain, check=check, base_map=base_map) + + verbose('base %s im_gens_end %s codomain %s check %s base_map %s' %(base_ring, im_gens_end, codomain, check, base_map)) + hom_on_base_recurs = base_ring.hom(im_gens_end, codomain=codomain, check=check, base_map=base_map) + verbose('hom_on_base_recurs %s' %(hom_on_base_recurs)) + + cover_ring = self.cover_ring() + hom_from_cover = cover_ring.hom(im_gens_start, codomain=codomain, check=check, base_map=hom_on_base_recurs) + lift = self.lifting_map() + return hom_from_cover*lift + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # local methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # global methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def is_completely_split(self): + r""" + Return True if the defining polynomial of ``self`` splits into linear factors over ``self``. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: S. = SplittingAlgebra(x^3 - u*x^2 + v*x - w) + sage: S.is_completely_split() + True + sage: S.base_ring().is_completely_split() + False + """ + if len(self.splitting_roots()) < self.defining_polynomial().degree(): + return False + return True + + @cached_method + def lifting_map(self): + r""" + Return a section map from ``self`` to the cover ring. It is implemented according + to the same named method of :class:`~sage.rings.quotient_ring.QuotientRing_nc`. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: x = polygen(ZZ) + sage: S = SplittingAlgebra(x^2+1, ('I',)) + sage: lift = S.lifting_map() + sage: lift(5) + 5 + sage: r1, r2 =S.splitting_roots() + sage: lift(r1) + I + """ + from sage.rings.morphism import RingMap_lift + return RingMap_lift(self, self.cover_ring()) + + def splitting_roots(self): + r""" + Return the roots of the splitted equation. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: x = polygen(ZZ) + sage: S = SplittingAlgebra(x^2+1, ('I',)) + sage: S.splitting_roots() + [I, -I] + """ + + return self._splitting_roots + + @cached_method + def gens_recursive(self): + r""" + Return all generators recursively. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ) + sage: x = polygen(L) + sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) + sage: S.gens_recursive() + (Y, X, u, v, w) + """ + base_ring = self.base_ring() + res = self.gens() + if isinstance(base_ring, SplittingAlgebra): + return res + base_ring.gens_recursive() + return res + base_ring.gens() + + + @cached_method + def scalar_base_ring(self): + r""" + Return the ring of scalars of ``self`` (considered as an algebra) + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ) + sage: x = polygen(L) + sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) + sage: S.base_ring() + Factorization Algebra of x^3 - u*x^2 + v*x - w with roots [X] + over Multivariate Laurent Polynomial Ring in u, v, w over Integer Ring + sage: S.scalar_base_ring() + Multivariate Laurent Polynomial Ring in u, v, w over Integer Ring + """ + base_ring = self.base_ring() + if isinstance(base_ring, SplittingAlgebra): + if base_ring.is_completely_split(): + # another splitting algebra independent of self + return base_ring + else: + return base_ring.scalar_base_ring() + return base_ring + + @cached_method + def defining_polynomial(self): + r""" + Return the defining polynomial of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import SplittingAlgebra + sage: L. = LaurentPolynomialRing(ZZ) + sage: x = polygen(L) + sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) + sage: S.defining_polynomial() + x^3 - u*x^2 + v*x - w + """ + base_ring = self.base_ring() + if isinstance(base_ring, SplittingAlgebra): + if base_ring.is_completely_split(): + # another splitting algebra independent of self + return self._defining_polynomial + else: + return base_ring.defining_polynomial() + return self._defining_polynomial + + + + + + + + + + + + + + + + +# -------------------------------------------------------------------------------------------- +# ============================================================================================ +# Utility function to create the roots of a polynomial in an appropriate extension ring +# ============================================================================================ +# -------------------------------------------------------------------------------------------- + +def solve_with_extension(monic_polynomial, root_names=None, var='x', flatten=False, warning=True): + r""" + Return all roots of a monic polynomial in its base ring or in an appropriate + extension ring, as far as possible. + + INPUT: + + - ``monic_polynomial`` -- the monic polynomial whose roots should be created + - ``root_names`` -- names for the indeterminates needed to define the + splitting algebra of the ``monic_polynomial`` (if necessary and possible) + - ``var`` -- (optional string, default 'x') for the indeterminate needed to define the + splitting field of the ``monic_polynomial`` (if necessary and possible) + - ``flatten`` -- (optional boolean, default = True) if set True the roots will not be + given as a list of pairs ``(root, multiplicity)`` but as a list of roots repeated according + to their multiplicity + - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) + to suppress a warning which will be thrown whenever it cannot be checked that + the Galois group of ``monic_polynomial`` is maximal + + OUTPUT: + + List of tuples ``(root, multiplicity)`` respectively list of roots repeated according + to their multiplicity if option ``flatten`` is ``True``. + + + EXAMPLES:: + + sage: from sage.algebras.splitting_algebra import solve_with_extension + sage: t = polygen(ZZ) + sage: p = t^2 -2*t +1 + sage: solve_with_extension(p, flatten=True ) + [1, 1] + sage: solve_with_extension(p) + [(1, 2)] + + sage: cp5 = cyclotomic_polynomial(5, var='T').change_ring(UniversalCyclotomicField()) + sage: solve_with_extension(cp5) + [(E(5), 1), (E(5)^4, 1), (E(5)^2, 1), (E(5)^3, 1)] + sage: _[0][0].parent() + Universal Cyclotomic Field + """ + + def create_roots(monic_polynomial, warning=True): + r""" + This internal function creates all roots of a polynomial in an appropriate extension ring + assuming that none of the roots is contained its base ring. + + It first tries to create the splitting field of the given polynomial. If this is not + faithful the splitting algebra will be created. + + INPUT: + + - ``monic_polynomial`` -- the monic polynomial whose roots should be created + - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) + to suppress a warning which will be thrown whenever it cannot be checked that + the Galois group of ``monic_polynomial`` is maximal + """ + + parent = monic_polynomial.parent() + base_ring = parent.base_ring() + + try: + ext_field, embed = monic_polynomial.splitting_field(var, map=True) + + if embed.domain() != base_ring: + # in this case the SplittingAlgebra is preferred + raise NotImplementedError + + # ------------------------------------------------------------------------------------- + # in some cases the embedding of the base_ring in ext_field can not be obtained + # as coercion + # ------------------------------------------------------------------------------------- + reset_coercion = False + from sage.rings.number_field.number_field import NumberField_generic + if isinstance(base_ring, NumberField_generic): + reset_coercion = True + elif base_ring.is_finite() == True and base_ring.is_prime_field() == False: + reset_coercion = True + if reset_coercion == True: + ext_field._unset_coercions_used() + ext_field.register_coercion(embed) + ext_field.register_conversion(embed) + + verbose("splitting field %s defined" %(ext_field)) + pol_emb = monic_polynomial.change_ring(ext_field) + roots = pol_emb.roots() + except NotImplementedError: + ext_ring = SplittingAlgebra(monic_polynomial, name_list, warning=warning) + verbose("splitting algebra %s defined" %(ext_ring)) + roots = [(r, 1) for r in ext_ring.splitting_roots()] + return roots + + + deg_pol = monic_polynomial.degree() + if not root_names: + from sage.structure.category_object import normalize_names + root_names = normalize_names(deg_pol-1, 'r') + name_list = list(root_names) + root_list = [] + try: + root_list = monic_polynomial.roots() + except (TypeError, ValueError, NotImplementedError): + pass + + if len(root_list) == 0 : + # ------------------------------------------------------------------------------ + # no roots found: find roots in an appropriate extension ring + # ------------------------------------------------------------------------------ + verbose("no roots in base_ring") + if len(name_list) > deg_pol -1 : + name_list = [name_list[i] for i in range(deg_pol-1 )] + roots = create_roots(monic_polynomial, warning=warning) + + else: + # ------------------------------------------------------------------------------ + # root calculation was possible but maybe some more roots in an apropriate + # extension ring can be constructed. + # ------------------------------------------------------------------------------ + num_roots = sum(m for r, m in root_list) + if num_roots < deg_pol: + h = monic_polynomial.variables()[0] + divisor = monic_polynomial.base_ring().one() + for r, m in root_list: + divisor *= (h - r)**m + q, r = monic_polynomial.quo_rem(divisor) + if len(name_list) > deg_pol - num_roots -1 : + name_list = [name_list[i] for i in range(deg_pol - num_roots -1 )] + verbose("%d root found in base ring, now solving %s" %(num_roots,q)) + missing_roots = create_roots(q, warning=True) + roots = root_list + missing_roots + else: + roots = root_list + verbose("all roots in base ring") + + if flatten: + from sage.misc.flatten import flatten + return flatten([[r]*m for r, m in roots]) + return roots From a284512f6348e8141d8f395079f7577ec00e4388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 May 2020 13:37:58 +0200 Subject: [PATCH 225/476] spring cleanup for combinat/core.py --- src/sage/combinat/core.py | 130 ++++++++++++++++++++------------- src/sage/combinat/k_tableau.py | 8 +- 2 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/sage/combinat/core.py b/src/sage/combinat/core.py index a4e8370451a..3e699ee4295 100644 --- a/src/sage/combinat/core.py +++ b/src/sage/combinat/core.py @@ -32,7 +32,6 @@ from sage.combinat.partition import Partitions, Partition from sage.combinat.combinat import CombinatorialElement from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.functions.other import floor from sage.combinat.combinatorial_map import combinatorial_map @@ -53,7 +52,7 @@ class Core(CombinatorialElement): @staticmethod def __classcall_private__(cls, part, k): r""" - Implements the shortcut ``Core(part, k)`` to ``Cores(k,l)(part)`` + Implement the shortcut ``Core(part, k)`` to ``Cores(k,l)(part)`` where `l` is the length of the core. TESTS:: @@ -74,7 +73,7 @@ def __classcall_private__(cls, part, k): return part part = Partition(part) if not part.is_core(k): - raise ValueError("%s is not a %s-core"%(part, k)) + raise ValueError("%s is not a %s-core" % (part, k)) l = sum(part.k_boundary(k).row_lengths()) return Cores(k, l)(part) @@ -100,11 +99,13 @@ def __init__(self, parent, core): k = parent.k part = Partition(core) if not part.is_core(k): - raise ValueError("%s is not a %s-core"%(part, k)) + raise ValueError("%s is not a %s-core" % (part, k)) CombinatorialElement.__init__(self, parent, core) def __eq__(self, other): """ + Test for equality. + EXAMPLES:: sage: c = Core([4,2,1,1],5) @@ -118,14 +119,33 @@ def __eq__(self, other): False """ if isinstance(other, Core): - return self._list == other._list and self.parent().k == other.parent().k - else: - return False + return (self._list == other._list and + self.parent().k == other.parent().k) + return False + + def __ne__(self, other): + """ + Test for un-equality. + + EXAMPLES:: + + sage: c = Core([4,2,1,1],5) + sage: d = Core([4,2,1,1],5) + sage: e = Core([4,2,1,1],6) + sage: c != [4,2,1,1] + True + sage: c != d + False + sage: c != e + True + """ + return not (self == other) def __hash__(self): """ - Computes the hash of ``self`` by computing the hash of the + Compute the hash of ``self`` by computing the hash of the underlying list and of the additional parameter. + The hash is cached and stored in ``self._hash``. EXAMPLES:: @@ -170,7 +190,7 @@ def _latex_(self): def k(self): r""" - Returns `k` of the `k`-core ``self``. + Return `k` of the `k`-core ``self``. EXAMPLES:: @@ -183,7 +203,7 @@ def k(self): @combinatorial_map(name="to partition") def to_partition(self): r""" - Turns the core ``self`` into the partition identical to ``self``. + Turn the core ``self`` into the partition identical to ``self``. EXAMPLES:: @@ -198,7 +218,7 @@ def to_bounded_partition(self): r""" Bijection between `k`-cores and `(k-1)`-bounded partitions. - Maps the `k`-core ``self`` to the corresponding `(k-1)`-bounded partition. + This maps the `k`-core ``self`` to the corresponding `(k-1)`-bounded partition. This bijection is achieved by deleting all cells in ``self`` of hook length greater than `k`. @@ -213,7 +233,7 @@ def to_bounded_partition(self): def size(self): r""" - Returns the size of ``self`` as a partition. + Return the size of ``self`` as a partition. EXAMPLES:: @@ -226,7 +246,7 @@ def size(self): def length(self): r""" - Returns the length of ``self``. + Return the length of ``self``. The length of a `k`-core is the size of the corresponding `(k-1)`-bounded partition which agrees with the length of the corresponding Grassmannian element, @@ -270,11 +290,12 @@ def to_grassmannian(self): [0 1 0] [0 0 1] """ - return self.to_bounded_partition().from_kbounded_to_grassmannian(self.k()-1) + bp = self.to_bounded_partition() + return bp.from_kbounded_to_grassmannian(self.k() - 1) def affine_symmetric_group_simple_action(self, i): r""" - Returns the action of the simple transposition `s_i` of the affine symmetric group on ``self``. + Return the action of the simple transposition `s_i` of the affine symmetric group on ``self``. This gives the action of the affine symmetric group of type `A_k^{(1)}` on the `k`-core ``self``. If ``self`` has outside (resp. inside) corners of content `i` modulo `k`, then @@ -304,11 +325,13 @@ def affine_symmetric_group_simple_action(self, i): """ mu = self.to_partition() corners = mu.outside_corners() - corners = [ p for p in corners if mu.content(p[0],p[1])%self.k()==i ] - if corners == []: + corners = [p for p in corners + if mu.content(p[0], p[1]) % self.k() == i] + if not corners: corners = mu.corners() - corners = [ p for p in corners if mu.content(p[0],p[1])%self.k()==i ] - if corners == []: + corners = [p for p in corners + if mu.content(p[0], p[1]) % self.k() == i] + if not corners: return self for p in corners: mu = mu.remove_cell(p[0]) @@ -317,7 +340,7 @@ def affine_symmetric_group_simple_action(self, i): mu = mu.add_cell(p[0]) return Core(mu, self.k()) - def affine_symmetric_group_action(self, w, transposition = False): + def affine_symmetric_group_action(self, w, transposition=False): r""" Return the (left) action of the affine symmetric group on ``self``. @@ -384,13 +407,15 @@ def _transposition_to_reduced_word(self, t): [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 1] """ k = self.k() - if (t[0]-t[1])%k == 0: + if (t[0] - t[1]) % k == 0: raise ValueError("t_0 and t_1 cannot be equal mod k") if t[0] > t[1]: - return self._transposition_to_reduced_word([t[1],t[0]]) + return self._transposition_to_reduced_word([t[1], t[0]]) else: - return [i%k for i in range(t[0],t[1]-floor((t[1]-t[0])/k))] + [(t[1]-floor((t[1]-t[0])/k)-2-i)%(k) for i in - range(t[1]-floor((t[1]-t[0])/k)-t[0]-1)] + resu = [i % k for i in range(t[0], t[1] - (t[1] - t[0]) // k)] + resu += [(t[1] - (t[1] - t[0]) // k - 2 - i) % k + for i in range(t[1] - (t[1] - t[0]) // k - t[0] - 1)] + return resu def weak_le(self, other): r""" @@ -402,7 +427,7 @@ def weak_le(self, other): OUTPUT: a boolean - Returns whether ``self`` <= ``other`` in weak order. + This returns whether ``self`` <= ``other`` in weak order. EXAMPLES:: @@ -434,7 +459,7 @@ def weak_le(self, other): def weak_covers(self): r""" - Returns a list of all elements that cover ``self`` in weak order. + Return a list of all elements that cover ``self`` in weak order. EXAMPLES:: @@ -448,8 +473,8 @@ def weak_covers(self): """ w = self.to_grassmannian() S = w.upper_covers(side='left') - S = [x for x in S if x.is_affine_grassmannian()] - return [ x.affine_grassmannian_to_core() for x in set(S) ] + S = (x for x in S if x.is_affine_grassmannian()) + return [x.affine_grassmannian_to_core() for x in set(S)] def strong_le(self, other): r""" @@ -461,7 +486,7 @@ def strong_le(self, other): OUTPUT: a boolean - Returns whether ``self`` <= ``other`` in Bruhat (or strong) order. + This returns whether ``self`` <= ``other`` in Bruhat (or strong) order. EXAMPLES:: @@ -479,7 +504,7 @@ def strong_le(self, other): ValueError: The two cores do not have the same k """ if type(self) is type(other): - if self.k()!=other.k(): + if self.k() != other.k(): raise ValueError("The two cores do not have the same k") else: other = Core(other, self.k()) @@ -495,8 +520,8 @@ def contains(self, other): OUTPUT: a boolean - Returns ``True`` if the Ferrers diagram of ``self`` contains the - Ferrers diagram of other. + This returns ``True`` if the Ferrers diagram of ``self`` contains the + Ferrers diagram of ``other``. EXAMPLES:: @@ -513,7 +538,7 @@ def contains(self, other): def strong_covers(self): r""" - Returns a list of all elements that cover ``self`` in strong order. + Return a list of all elements that cover ``self`` in strong order. EXAMPLES:: @@ -524,12 +549,12 @@ def strong_covers(self): sage: c.strong_covers() [[5, 3, 1], [4, 2, 1, 1]] """ - S = Cores(self.k(), length=self.length()+1) - return [ ga for ga in S if ga.contains(self) ] + S = Cores(self.k(), length=self.length() + 1) + return [ga for ga in S if ga.contains(self)] def strong_down_list(self): r""" - Returns a list of all elements that are covered by ``self`` in strong order. + Return a list of all elements that are covered by ``self`` in strong order. EXAMPLES:: @@ -540,11 +565,13 @@ def strong_down_list(self): sage: c.strong_down_list() [[4, 2], [3, 1, 1]] """ - if self==[]: + if not self: return [] - return [ga for ga in Cores(self.k(), length=self.length()-1) if self.contains(ga)] + return [ga for ga in Cores(self.k(), length=self.length() - 1) + if self.contains(ga)] + -def Cores(k, length = None, **kwargs): +def Cores(k, length=None, **kwargs): r""" A `k`-core is a partition from which no rim hook of size `k` can be removed. Alternatively, a `k`-core is an integer partition such that the Ferrers @@ -586,12 +613,13 @@ def Cores(k, length = None, **kwargs): [4, 1, 1] """ if length is None and 'size' in kwargs: - return Cores_size(k,kwargs['size']) + return Cores_size(k, kwargs['size']) elif length is not None: - return Cores_length(k,length) + return Cores_length(k, length) else: raise ValueError("You need to either specify the length or size of the cores considered!") + class Cores_length(UniqueRepresentation, Parent): r""" The class of `k`-cores of length `n`. @@ -607,7 +635,7 @@ def __init__(self, k, n): """ self.k = k self.n = n - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): """ @@ -616,11 +644,11 @@ def _repr_(self): sage: repr(Cores(4, 3)) #indirect doctest '4-Cores of length 3' """ - return "%s-Cores of length %s"%(self.k,self.n) + return "%s-Cores of length %s" % (self.k, self.n) def list(self): r""" - Returns the list of all `k`-cores of length `n`. + Return the list of all `k`-cores of length `n`. EXAMPLES:: @@ -628,7 +656,8 @@ def list(self): sage: C.list() [[4, 2], [3, 1, 1], [2, 2, 1, 1]] """ - return [la.to_core(self.k-1) for la in Partitions(self.n, max_part=self.k-1)] + return [la.to_core(self.k - 1) + for la in Partitions(self.n, max_part=self.k - 1)] def from_partition(self, part): r""" @@ -671,7 +700,7 @@ def __init__(self, k, n): """ self.k = k self.n = n - Parent.__init__(self, category = FiniteEnumeratedSets()) + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): """ @@ -680,11 +709,11 @@ def _repr_(self): sage: repr(Cores(4, size = 3)) #indirect doctest '4-Cores of size 3' """ - return "%s-Cores of size %s"%(self.k,self.n) + return "%s-Cores of size %s" % (self.k, self.n) def list(self): r""" - Returns the list of all `k`-cores of size `n`. + Return the list of all `k`-cores of size `n`. EXAMPLES:: @@ -692,11 +721,12 @@ def list(self): sage: C.list() [[3, 1], [2, 1, 1]] """ - return [ Core(x, self.k) for x in Partitions(self.n) if x.is_core(self.k) ] + return [Core(x, self.k) for x in Partitions(self.n) + if x.is_core(self.k)] def from_partition(self, part): r""" - Converts the partition ``part`` into a core (as the identity map). + Convert the partition ``part`` into a core (as the identity map). This is the inverse method to :meth:`to_partition`. diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 8770fb9c464..ac6cd85bd84 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -1277,7 +1277,7 @@ def __init__(self, k, shape, weight): sage: TestSuite(T).run() """ self.k = k - self._skew = shape[1]!=[] + self._skew = bool(shape[1]) self._outer_shape = shape[0] self._inner_shape = shape[1] self._shape = (self._outer_shape, self._inner_shape) @@ -1743,7 +1743,7 @@ def __init__(self, k, shape, weight): sage: TestSuite(T).run() """ self.k = k - self._skew = shape[1]!=[] + self._skew = bool(shape[1]) self._outer_shape = Partition(shape[0]) self._inner_shape = Partition(shape[1]) self._shape = (self._outer_shape, self._inner_shape) @@ -2164,7 +2164,7 @@ def __init__(self, k, shape, weight): sage: TestSuite(T).run() # long time """ self.k = k - self._skew = shape[1]!=[] + self._skew = bool(shape[1]) self._outer_shape = Core(shape[0], k+1) self._inner_shape = Core(shape[1], k+1) self._shape = (self._outer_shape, self._inner_shape) @@ -4056,7 +4056,7 @@ def shape(self): sage: StrongTableaux( 4, [[2,1], [1]] ).shape() ([2, 1], [1]) """ - if self._inner_shape != []: + if bool(self._inner_shape): return (self._outer_shape, self._inner_shape) return self._outer_shape From 697276b88fdb0ef50348d8b29b1e27568db76aef Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 14:01:17 +0100 Subject: [PATCH 226/476] 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 227/476] 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 228/476] 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 229/476] 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 230/476] 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 231/476] 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 232/476] 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 233/476] 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 234/476] 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 235/476] 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 236/476] 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 08c4b577de5697e8188d68e0c31cf853d92a4a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 21 May 2020 10:32:52 +0200 Subject: [PATCH 237/476] fix detail --- src/sage/combinat/k_tableau.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index ac6cd85bd84..fd90898eaab 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -4056,7 +4056,7 @@ def shape(self): sage: StrongTableaux( 4, [[2,1], [1]] ).shape() ([2, 1], [1]) """ - if bool(self._inner_shape): + if self._inner_shape: return (self._outer_shape, self._inner_shape) return self._outer_shape From 870170502124a52fbcf32b85c6a32d4e2b876edb Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 21 May 2020 10:16:17 +0100 Subject: [PATCH 238/476] 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 239/476] 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 240/476] 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 241/476] 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 99eaaabbe8bcf5c53783c8a00d84b35685271c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 21 May 2020 19:05:33 +0200 Subject: [PATCH 242/476] some care for Coxeter and Reflection groups (with optional gap3) --- .../finite_complex_reflection_groups.py | 16 +++++++++++++- .../root_system/reflection_group_complex.py | 22 +++++++++---------- .../root_system/reflection_group_element.pyx | 8 +++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 60fbb8d97be..82f3800aa62 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -860,6 +860,8 @@ def noncrossing_partition_lattice(self, c=None, L=None, L = list(self.absolute_order_ideal(gens=c, in_unitary_group=in_unitary_group, return_lengths=True)) + else: + L = [(pi, pi.reflection_length()) for pi in L] rels = [] ref_lens = {pi:l for (pi, l) in L} for (pi, l) in L: @@ -980,8 +982,20 @@ def absolute_poset(self, in_unitary_group=False): Irreducible complex reflection group of rank 2 and type ST4 sage: W.absolute_poset() # optional - gap3 Finite poset containing 24 elements + + TESTS:: + + sage: W1 = CoxeterGroup(['A',2]) + sage: W2 = WeylGroup(['A',2]) + sage: W3 = SymmetricGroup(3) + sage: W1.absolute_poset() + Finite poset containing 6 elements + sage: W2.absolute_poset() + Finite poset containing 6 elements + sage: W3.absolute_poset() + Finite poset containing 6 elements """ - return self.noncrossing_partition_lattice(L=self, in_unitary_group=in_unitary_group) + return self.noncrossing_partition_lattice(L=tuple(self), in_unitary_group=in_unitary_group) class WellGenerated(CategoryWithAxiom): diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 0567f8bf304..82d6f83744e 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -216,10 +216,9 @@ from sage.modules.free_module_element import vector from sage.combinat.root_system.cartan_matrix import CartanMatrix from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField - - from sage.misc.sage_eval import sage_eval + class ComplexReflectionGroup(UniqueRepresentation, PermutationGroup_generic): """ A complex reflection group given as a permutation group. @@ -478,7 +477,7 @@ def distinguished_reflections(self): sage: W = ReflectionGroup((1,1,3),hyperplane_index_set=['a','b','c']) # optional - gap3 sage: W.distinguished_reflections() # optional - gap3 - Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)} + Finite family {'a': (1,4)(2,3)(5,6), 'b': (1,3)(2,5)(4,6), 'c': (1,5)(2,4)(3,6)} sage: W = ReflectionGroup((3,1,1)) # optional - gap3 sage: W.distinguished_reflections() # optional - gap3 @@ -675,7 +674,7 @@ def reflections(self): sage: W = ReflectionGroup((1,1,3),reflection_index_set=['a','b','c']) # optional - gap3 sage: W.reflections() # optional - gap3 - Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)} + Finite family {'a': (1,4)(2,3)(5,6), 'b': (1,3)(2,5)(4,6), 'c': (1,5)(2,4)(3,6)} sage: W = ReflectionGroup((3,1,1)) # optional - gap3 sage: W.reflections() # optional - gap3 @@ -967,9 +966,8 @@ def conjugacy_classes_representatives(self): [1, 2, 1, 2, 1, 3, 2, 1, 2, 1, 3, 2, 1, 2, 3]] """ # This can be converted to usual GAP - S = str(gap3('List(ConjugacyClasses(%s),Representative)'%self._gap_group._name)) - exec('_conjugacy_classes_representatives=' + _gap_return(S)) - return _conjugacy_classes_representatives + S = str(gap3('List(ConjugacyClasses(%s),Representative)' % self._gap_group._name)) + return sage_eval(_gap_return(S), {'self': self}) def conjugacy_classes(self): r""" @@ -1318,7 +1316,7 @@ def independent_roots(self): basis = {} for ind in self._index_set: vec = Delta[ind] - if Matrix(basis.values()+[vec]).rank() == len(basis) + 1: + if Matrix(list(basis.values()) + [vec]).rank() == len(basis) + 1: basis[ind] = vec return Family(basis) @@ -1367,7 +1365,7 @@ def roots(self): (0, 0, 0, -E(3), E(3)^2), (0, 0, 0, E(3)^2, -E(3)^2), (0, 0, 0, -E(3)^2, E(3)^2)] """ - roots = [vector(sage_eval(str(root).replace("^","**"))) + roots = [vector(sage_eval(str(root).replace("^", "**"))) for root in self._gap_group.roots] for v in roots: v.set_immutable() @@ -1382,15 +1380,15 @@ def braid_relations(self): sage: W = ReflectionGroup((1,1,3)) # optional - gap3 sage: W.braid_relations() # optional - gap3 - [[[2, 1, 2], [1, 2, 1]]] + [[[1, 2, 1], [2, 1, 2]]] sage: W = ReflectionGroup((2,1,3)) # optional - gap3 sage: W.braid_relations() # optional - gap3 - [[[2, 1, 2, 1], [1, 2, 1, 2]], [[3, 1], [1, 3]], [[3, 2, 3], [2, 3, 2]]] + [[[1, 2, 1, 2], [2, 1, 2, 1]], [[1, 3], [3, 1]], [[2, 3, 2], [3, 2, 3]]] sage: W = ReflectionGroup((2,2,3)) # optional - gap3 sage: W.braid_relations() # optional - gap3 - [[[2, 1, 2], [1, 2, 1]], [[3, 1], [1, 3]], [[3, 2, 3], [2, 3, 2]]] + [[[1, 2, 1], [2, 1, 2]], [[1, 3], [3, 1]], [[2, 3, 2], [3, 2, 3]]] """ if self.is_real(): return super(ComplexReflectionGroup,self).braid_relations() diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index ed552674922..fc7977e0335 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -423,7 +423,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): (1,2,6)(3,4,5) True (1,5)(2,4)(3,6) True """ - return PermutationGroupElement(self) + W = self._parent + return PermutationGroupElement(self, W) #@cached_in_parent_method def fix_space(self): @@ -465,8 +466,8 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): Basis matrix: [ 1 -1] - sage: W = ReflectionGroup(23) # optional - gap3 - sage: W.an_element().fix_space() # optional - gap3 + sage: W = ReflectionGroup(23) # optional - gap3 + sage: W.gen(0).fix_space() # optional - gap3 Vector space of degree 3 and dimension 2 over Universal Cyclotomic Field Basis matrix: [0 1 0] @@ -1175,4 +1176,3 @@ def _gap_return(S, coerce_obj='self'): S = S.replace(' ','').replace('\n','') S = S.replace(',(','\',check=False),%s(\'('%coerce_obj).replace('[','[%s(\''%coerce_obj).replace(']','\',check=False)]') return S - From b86ae754ade5a1b5ad7afcdc684d5d0a6485c52f Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Thu, 21 May 2020 23:42:45 +0530 Subject: [PATCH 243/476] 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 1777fad4b5bedcb34286e6064bf20d2d02231a88 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Fri, 22 May 2020 16:21:13 +0530 Subject: [PATCH 244/476] 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 245/476] 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 2750aa2dea0a9d54eec7b8710c06e73424be8507 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:21:40 +0200 Subject: [PATCH 246/476] added hash for reflection group element that is not only the abstract group --- src/sage/combinat/root_system/reflection_group_element.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index ed552674922..fa3227b04b3 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -39,6 +39,9 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): """ An element in a complex reflection group. """ + def __hash__(self): + return hash(self.parent()) + hash(tuple(self.reduced_word())) + def reduced_word(self): r""" Return a word in the simple reflections to obtain ``self``. From 837b1aabbc03d8634f16a269e11be5ac32db5693 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:29:29 +0200 Subject: [PATCH 247/476] added hash docstring --- .../root_system/reflection_group_element.pyx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index fa3227b04b3..4e73f2fcee8 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -40,6 +40,42 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): An element in a complex reflection group. """ def __hash__(self): + r""" + Return a hash for this reflection group element. + This hash stores both the element as a reduced word and the parent group. + + EXAMPLES:: + + sage: W = ReflectionGroup(['A',5]) # optional - gap3 + sage: w = W.from_reduced_word([1,2,3,4,5]) # optional - gap3 + sage: hash(w) # optional - gap3 + -1527414595000039889 # 64-bit + + TESTS: + + Check that types B and C are hashed differently, see #29726:: + + sage: WB = ReflectionGroup(['B',2]) + sage: WC = ReflectionGroup(['C',2]) + sage: sorted(map(hash,WB)) + [-9223363287990922543, + -9223359857975062524, + -9223359857974062521, + -8737669435968786273, + -6694860314014793569, + -5510281656060039426, + -5510280573528544276, + -5433655748006305484] + sage: sorted(map(hash,WC)) + [-9223363287990922588, + -9223359857975062569, + -9223359857974062566, + -8737669435968786318, + -6694860314014793614, + -5510281656060039471, + -5510280573528544321, + -5433655748006305529] + """ return hash(self.parent()) + hash(tuple(self.reduced_word())) def reduced_word(self): From e811e33b20142ba33fb396207f94db9ca3c6387d Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:30:40 +0200 Subject: [PATCH 248/476] added hash docstring --- .../combinat/root_system/reflection_group_element.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 4e73f2fcee8..68a397b9bdf 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -55,9 +55,9 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): Check that types B and C are hashed differently, see #29726:: - sage: WB = ReflectionGroup(['B',2]) - sage: WC = ReflectionGroup(['C',2]) - sage: sorted(map(hash,WB)) + sage: WB = ReflectionGroup(['B',2]) # optional - gap3 + sage: WC = ReflectionGroup(['C',2]) # optional - gap3 + sage: sorted(map(hash,WB)) # optional - gap3 [-9223363287990922543, -9223359857975062524, -9223359857974062521, @@ -66,7 +66,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): -5510281656060039426, -5510280573528544276, -5433655748006305484] - sage: sorted(map(hash,WC)) + sage: sorted(map(hash,WC)) # optional - gap3 [-9223363287990922588, -9223359857975062569, -9223359857974062566, From 7234f424efa49a85b47be97b50b852446f9202a8 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:38:56 +0200 Subject: [PATCH 249/476] fixed bug when creating dihedral type reflection groups --- .../root_system/reflection_group_real.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 96cbbcd9431..b43eb190086 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -407,11 +407,27 @@ def cartan_type(self): sage: W = ReflectionGroup(['A',3], ['B',3]) # optional - gap3 sage: W.cartan_type() # optional - gap3 - A3xB3 relabelled by {1: 3, 2: 2, 3: 1} + A3xB3 relabelled by {1: 3, 2: 2, 3: 1} + + TESTS: + + Check that dihedral types are handled properly:: + + sage: W = ReflectionGroup(['I',3]); W # optional - gap3 + Irreducible real reflection group of rank 2 and type A2 + + sage: W = ReflectionGroup(['I',4]); W # optional - gap3 + Irreducible real reflection group of rank 2 and type C2 + + sage: W = ReflectionGroup(['I',5]); W # optional - gap3 + Irreducible real reflection group of rank 2 and type I2(5) """ if len(self._type) == 1: ct = self._type[0] - C = CartanType([ct['series'], ct['rank']]) + if ct['series'] == "I": + C = CartanType([ct['series'], ct['bond']]) + else: + C = CartanType([ct['series'], ct['rank']]) CG = C.coxeter_diagram() G = self.coxeter_diagram() return C.relabel(CG.is_isomorphic(G, edge_labels=True, certificate=True)[1]) From 8b3cee5ca2f39a996651ca80f2830ce36f98d934 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:52:59 +0200 Subject: [PATCH 250/476] updated doctests according to Frederic's suggestions --- .../root_system/reflection_group_element.pyx | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 68a397b9bdf..329ff38a3d6 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -42,39 +42,37 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): def __hash__(self): r""" Return a hash for this reflection group element. + This hash stores both the element as a reduced word and the parent group. EXAMPLES:: sage: W = ReflectionGroup(['A',5]) # optional - gap3 - sage: w = W.from_reduced_word([1,2,3,4,5]) # optional - gap3 - sage: hash(w) # optional - gap3 - -1527414595000039889 # 64-bit + sage: W_hash = set(hash(w) for w in W) # optional - gap3 + sage: len(W_hash) == W.cardinality() # optional - gap3 + True TESTS: Check that types B and C are hashed differently, see #29726:: - sage: WB = ReflectionGroup(['B',2]) # optional - gap3 - sage: WC = ReflectionGroup(['C',2]) # optional - gap3 - sage: sorted(map(hash,WB)) # optional - gap3 - [-9223363287990922543, - -9223359857975062524, - -9223359857974062521, - -8737669435968786273, - -6694860314014793569, - -5510281656060039426, - -5510280573528544276, - -5433655748006305484] - sage: sorted(map(hash,WC)) # optional - gap3 - [-9223363287990922588, - -9223359857975062569, - -9223359857974062566, - -8737669435968786318, - -6694860314014793614, - -5510281656060039471, - -5510280573528544321, - -5433655748006305529] + sage: WB = ReflectionGroup(['B',5]) # optional - gap3 + sage: WC = ReflectionGroup(['C',5]) # optional - gap3 + + sage: WB_hash = set(hash(w) for w in WB) # optional - gap3 + sage: WC_hash = set(hash(w) for w in WC) # optional - gap3 + + sage: len(WB_hash) == WB.cardinality() # optional - gap3 + True + + sage: len(WB_hash) == WB.cardinality() # optional - gap3 + True + + sage: len(WC_hash) == WC.cardinality() # optional - gap3 + True + + sage: WB_hash.intersection(WC_hash) # optional - gap3 + set() """ return hash(self.parent()) + hash(tuple(self.reduced_word())) From d9a58666bfb4030f7bd4c2d9135d18657f74662c Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 15:54:09 +0200 Subject: [PATCH 251/476] updated doctests according to Frederic's suggestions --- src/sage/combinat/root_system/reflection_group_element.pyx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 329ff38a3d6..e3c61ae3c85 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -65,9 +65,6 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: len(WB_hash) == WB.cardinality() # optional - gap3 True - sage: len(WB_hash) == WB.cardinality() # optional - gap3 - True - sage: len(WC_hash) == WC.cardinality() # optional - gap3 True From 2c9d4f06655bdd6c241887fe4597df8f77b1fc56 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Fri, 22 May 2020 17:17:19 +0200 Subject: [PATCH 252/476] used proper trac link --- src/sage/combinat/root_system/reflection_group_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index e3c61ae3c85..2ba35debfed 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -54,7 +54,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): TESTS: - Check that types B and C are hashed differently, see #29726:: + Check that types B and C are hashed differently, see :trac:`29726`:: sage: WB = ReflectionGroup(['B',5]) # optional - gap3 sage: WC = ReflectionGroup(['C',5]) # optional - gap3 From 0bc80845f0c939dd27f9fc99a29572c3da1d4e3f Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 22 May 2020 16:20:42 +0100 Subject: [PATCH 253/476] 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 25f72302aabc364e87d5c9e4c473d6f0ffa5b3da Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Sun, 24 May 2020 01:15:13 +0530 Subject: [PATCH 254/476] 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 255/476] 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 256/476] 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 4d87fe557d66678bc90db176a88e21d1a0c3d38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 25 May 2020 13:51:14 +0200 Subject: [PATCH 257/476] some little enhancements for STL 3D export --- src/sage/plot/plot3d/shapes2.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 7a8c4cebd79..07e00c048da 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -848,6 +848,18 @@ def threejs_repr(self, render_params): point = dict(point=center, size=size, color=color, opacity=opacity) return [('point', point)] + def stl_binary_repr(self, render_params): + """ + Return an empty list, as this is not useful for STL export. + + EXAMPLES:: + + sage: P = point3d((1,2,3)).translate(-1, -2, -3) + sage: P.stl_binary_repr(P.default_render_params()) + [] + """ + return [] + class Line(PrimitiveObject): r""" @@ -1215,6 +1227,18 @@ def threejs_repr(self, render_params): reprs.append(('line', line)) return reprs + def stl_binary_repr(self, render_params): + """ + Return an empty list, as this is not useful for STL export. + + EXAMPLES:: + + sage: L = line3d([(1,2,3), (4,5,6)]).translate(-1, -2, -3) + sage: L.stl_binary_repr(L.default_render_params()) + [] + """ + return [] + @rename_keyword(alpha='opacity') def point3d(v, size=5, **kwds): From ef23d2f124004b586ee5b3b06aaf1f9077677968 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 25 May 2020 15:08:20 +0100 Subject: [PATCH 258/476] 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 259/476] 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 556f496f993f3d949d47fb20b7da83d1af0fbd60 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Mon, 25 May 2020 21:41:01 +0530 Subject: [PATCH 260/476] FIXED --- src/sage/graphs/generic_graph.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index e00570bc2cc..4381364b4fe 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16958,7 +16958,6 @@ def weight_function(e): return networkx.single_source_dijkstra_path_length(G, u) elif algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost', None]: - self.weighted(True) from sage.graphs.base.boost_graph import shortest_paths return shortest_paths(self, u, weight_function, algorithm)[0] From 7de03008dc6315bf93919e784697f112a493cd76 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Mon, 25 May 2020 18:47:55 +0200 Subject: [PATCH 261/476] another proposal --- src/sage/rings/fraction_field.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 15328d7bbe8..2342dc64237 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -698,12 +698,8 @@ def resolve_fractions(x, y): try: return self._element_class(self, x, y, coerce=coerce) except TypeError: - if not x != x0: - # Make one last attempt to convert x into ``self`` - x = self(x) - y *= x.denominator() - x = x.numerator() - return self._element_class(self, x, y, coerce=coerce) + if parent(x) is parent(x0): + raise def construction(self): """ From 8a32e38008a93e14d6199826224423318f244809 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 26 May 2020 13:44:10 +0900 Subject: [PATCH 262/476] Add L-polynomial to curves --- src/sage/schemes/curves/projective_curve.py | 75 ++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 592bb68dc65..f031ed25efb 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -115,7 +115,7 @@ from sage.matrix.all import matrix from sage.misc.all import add, sage_eval -from sage.rings.all import degree_lowest_rational_function +from sage.rings.all import degree_lowest_rational_function, IntegerRing from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import (number_field_elements_from_algebraics, @@ -2562,6 +2562,79 @@ def closed_points(self, degree=1): return points + @cached_method + def L_polynomial(self, name='t'): + """ + Return the L-polynomial of this possibly singular curve. + + INPUT: + + - ``name`` -- (default: ``t``) name of the variable of the polynomial + + EXAMPLES:: + + sage; A. = AffineSpace(GF(3), 2) + sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) + sage: Cbar = C.projective_closure() + sage: Cbar.L_polynomial() + 9*t^4 - 3*t^3 + t^2 - t + 1 + + """ + F = self.function_field() + L = F.L_polynomial() + + R = L.parent() + T = R.gen() + + f = R.one() + for p, places in self._singularities: + for place in places: + f = f * (1 - T**place.degree()) + f = f // (1 - T**p.degree()) + + return L * f + + def number_of_rational_points(self, r=1): + """ + Return the number of rational points of the curve with + constant field extended by degree ``r``. + + INPUT: + + - ``r`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage; A. = AffineSpace(GF(3), 2) + sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) + sage: Cbar = C.projective_closure() + sage: Cbar.number_of_rational_points(3) + 21 + sage: D = Cbar.change_ring(Cbar.base_ring().extension(3)) + sage: D.base_ring() + Finite Field in z3 of size 3^3 + sage: len(D.closed_points()) + 21 + + """ + q = self.base_ring().order() + L = self.L_polynomial() + Lp = L.derivative() + + R = IntegerRing()[[L.parent().gen()]] # power series ring + L = R(L) + Lp = R(Lp) + + previous_prec = R.default_prec() + R.set_default_prec(r) + + f = Lp / L + n = f[r-1] + q**r + 1 + + R.set_default_prec(previous_prec) + + return n + class IntegralProjectivePlaneCurve_finite_field(ProjectivePlaneCurve_finite_field, IntegralProjectiveCurve_finite_field): """ From 966ae578679fad8bbd25c12816537b3f21a8c310 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 26 May 2020 16:58:56 +1000 Subject: [PATCH 263/476] Fixing pyflakes warnings. --- src/sage/groups/raag.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 70438999c93..a4f210377d5 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -38,12 +38,9 @@ from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.combinat.root_system.coxeter_group import CoxeterGroup -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.fields import Fields from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.algebras.clifford_algebra import CliffordAlgebraElement from sage.typeset.ascii_art import ascii_art from sage.typeset.unicode_art import unicode_art @@ -704,7 +701,6 @@ def _repr_term(self, m): if len(m) == 0: return '1' term = '' - V = self for i in m: if len(term) != 0: term += '*' From 8ec934fcc2b995c5eac225cdcc599fe93a9fc0f5 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 26 May 2020 10:20:21 +0100 Subject: [PATCH 264/476] 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 12def0bb92bc69247cb6362d91a9ca6d3d768e47 Mon Sep 17 00:00:00 2001 From: Christian Stump Date: Tue, 26 May 2020 19:38:00 +0200 Subject: [PATCH 265/476] updated hash according to Travis' suggesion, speed factor 2 --- src/sage/combinat/root_system/reflection_group_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 2ba35debfed..ca3138e1fb0 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -71,7 +71,7 @@ cdef class ComplexReflectionGroupElement(PermutationGroupElement): sage: WB_hash.intersection(WC_hash) # optional - gap3 set() """ - return hash(self.parent()) + hash(tuple(self.reduced_word())) + return hash(self._parent) | hash(tuple(self._reduced_word)) def reduced_word(self): r""" From 26f2f05ddd75d25fafb08bd97401dc22c3350772 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 27 May 2020 20:24:36 +0900 Subject: [PATCH 266/476] Fix typos --- src/sage/schemes/curves/projective_curve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index f031ed25efb..b8932805386 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -2573,7 +2573,7 @@ def L_polynomial(self, name='t'): EXAMPLES:: - sage; A. = AffineSpace(GF(3), 2) + sage: A. = AffineSpace(GF(3), 2) sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: Cbar = C.projective_closure() sage: Cbar.L_polynomial() @@ -2605,7 +2605,7 @@ def number_of_rational_points(self, r=1): EXAMPLES:: - sage; A. = AffineSpace(GF(3), 2) + sage: A. = AffineSpace(GF(3), 2) sage: C = Curve(y^2 - x^5 - x^4 - 2*x^3 - 2*x - 2) sage: Cbar = C.projective_closure() sage: Cbar.number_of_rational_points(3) From caa93b15cc0f7975b33f4972c76433a8f5a1487c Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 27 May 2020 13:23:49 +0100 Subject: [PATCH 267/476] Initial commit --- src/sage/combinat/gelfand_tsetlin_patterns.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index 52d39ddb8c2..66bf0b3d322 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -509,6 +509,67 @@ def Tokuyama_coefficient(self, name='t'): return R.zero() return (t+1)**(self.number_of_special_entries()) * t**(self.number_of_boxes()) + + def bender_knuth_involution(self,i): + r""" + Return the image of ''self'' under the 'i'-th Bender-Knuth involution. + + If the triangle 'G' has size 'n' then this is defined for '0 < i < n'. + + This implements the construction of the Bender-Knuth involution using toggling + due to Berenstein-Kirillov. + + This agrees with the Bender-Knuth involution on semistandard tableaux. + + EXAMPLES:: + + sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]]) + sage: bender_knuth_involution(G,2) + [[5, 3, 2, 1, 0], [4, 3, 2, 0], [4, 2, 1], [3, 2], [3]] + + TESTS:: + + sage: all(all( bender_knuth_involution(G,i).to_tableau() == G.to_tableau().bender_knuth_involution(i) + for i in range(1,len(G)) ) for G in GelfandTsetlinPatterns(top_row=[3,3,3,0,0])) + True + + sage: G = GelfandTsetlinPattern([[2,1,0],[1,0],[0]]) + sage: bender_knuth_involution(G,0) + Traceback (most recent call last): + ... + ValueError: must have 0 < 0 < 3 + sage: bender_knuth_involution(G,3) + Traceback (most recent call last): + ... + ValueError: must have 0 < 3 < 3 + + """ + n = len(self) + + def toggle(i,j): + """ + Return the toggle of entry 'G[i][j]' in a Gelfand-Tsetlin pattern, 'G'. + """ + if i == n-1: + return self[n-2][0]+self[n-2][1]-self[n-1][0] + + if j == 0: + left = self[i-1][0] + else: + left = min(self[i-1][j], self[i+1][j-1]) + if j == n-i-1: + right = self[i-1][j+1] + else: + right = max(self[i-1][j+1], self[i+1][j]) + + return left + right - self[i][j] + + if not 0 < i < n: + raise ValueError(f"must have 0 < {i} < {n}") + r = n-i + result = copy(self) + result[r] = [toggle(r,s) for s in range(i)] + return result class GelfandTsetlinPatterns(UniqueRepresentation, Parent): """ From 348b838bf57912553c38b092b7000976d0c50474 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 27 May 2020 13:36:01 +0100 Subject: [PATCH 268/476] All tests passed! --- src/sage/combinat/gelfand_tsetlin_patterns.py | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index 66bf0b3d322..ae1de2faa15 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -509,50 +509,50 @@ def Tokuyama_coefficient(self, name='t'): return R.zero() return (t+1)**(self.number_of_special_entries()) * t**(self.number_of_boxes()) - def bender_knuth_involution(self,i): r""" Return the image of ''self'' under the 'i'-th Bender-Knuth involution. - + If the triangle 'G' has size 'n' then this is defined for '0 < i < n'. - + This implements the construction of the Bender-Knuth involution using toggling due to Berenstein-Kirillov. - + This agrees with the Bender-Knuth involution on semistandard tableaux. - + EXAMPLES:: - + sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]]) - sage: bender_knuth_involution(G,2) - [[5, 3, 2, 1, 0], [4, 3, 2, 0], [4, 2, 1], [3, 2], [3]] - + sage: G.bender_knuth_involution(2) + [[5, 3, 2, 1, 0], [4, 3, 2, 0], [4, 2, 1], [4, 1], [3]] + TESTS:: - - sage: all(all( bender_knuth_involution(G,i).to_tableau() == G.to_tableau().bender_knuth_involution(i) + + sage: all(all( G.bender_knuth_involution(i).to_tableau() == G.to_tableau().bender_knuth_involution(i) \ for i in range(1,len(G)) ) for G in GelfandTsetlinPatterns(top_row=[3,3,3,0,0])) True - + sage: G = GelfandTsetlinPattern([[2,1,0],[1,0],[0]]) - sage: bender_knuth_involution(G,0) + sage: G.bender_knuth_involution(0) Traceback (most recent call last): ... ValueError: must have 0 < 0 < 3 - sage: bender_knuth_involution(G,3) + sage: G.bender_knuth_involution(3) Traceback (most recent call last): ... ValueError: must have 0 < 3 < 3 - + """ + from copy import copy n = len(self) - + def toggle(i,j): """ Return the toggle of entry 'G[i][j]' in a Gelfand-Tsetlin pattern, 'G'. - """ + """ if i == n-1: return self[n-2][0]+self[n-2][1]-self[n-1][0] - + if j == 0: left = self[i-1][0] else: @@ -561,9 +561,9 @@ def toggle(i,j): right = self[i-1][j+1] else: right = max(self[i-1][j+1], self[i+1][j]) - + return left + right - self[i][j] - + if not 0 < i < n: raise ValueError(f"must have 0 < {i} < {n}") r = n-i From fb14d9e0177defdc6e0f0615e7d70f2ac7b1dc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Cuevas-Rozo?= Date: Wed, 29 May 2019 13:16:43 +0200 Subject: [PATCH 269/476] Methods for computing on finite simplicial sets and chain coimplexes were added. Computation of homotopy groups added. --- src/sage/interfaces/kenzo.py | 413 ++++++++++++++++++++++++++++++++++- 1 file changed, 410 insertions(+), 3 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 976983a06f8..a38215e4e38 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -31,8 +31,14 @@ from sage.rings.integer_ring import ZZ from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups +from sage.matrix.all import matrix +from sage.homology.chain_complex import ChainComplex +from sage.homology.simplicial_set import AbstractSimplex, SimplicialSet + from sage.libs.ecl import EclObject, ecl_eval, EclListIterator +from sage.env import SAGE_LOCAL +from sys import version # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we @@ -57,12 +63,37 @@ moore = EclObject("moore") k_z = EclObject("k-z") k_z2 = EclObject("k-z2") +k_zp = EclObject("k-zp") echcm = EclObject("echcm") loop_space = EclObject("loop-space") tnsr_prdc = EclObject("tnsr-prdc") typep = EclObject("typep") classifying_space = EclObject("classifying-space") suspension = EclObject("suspension") +homotopy_list = EclObject("homotopy-list") +nth = EclObject("nth") +entry = EclObject("entry") +nlig = EclObject("nlig") +ncol = EclObject("ncol") +array_dimensions = EclObject("array-dimensions") +convertmatrice = EclObject("convertmatrice") +make_array_to_lists = EclObject("make-array-to-lists") +make_array_from_lists = EclObject("make-array-from-lists") +chcm_mat2 = EclObject("chcm-mat2") +build_finite_ss2 = EclObject("build-finite-ss2") +gmsm = EclObject("gmsm") +dgop = EclObject("dgop") +dgop_ext_int = EclObject("dgop-ext-int") +dgop_int_ext = EclObject("dgop-int-ext") +basis_aux1 = EclObject("basis_aux1") +orgn_aux1 = EclObject("orgn_aux1") +dffr_aux1 = EclObject("dffr_aux1") +kabstractsimplex_aux1 = EclObject("kabstractsimplex_aux1") +kchaincomplex_aux1 = EclObject("kchaincomplex_aux1") +sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") + + +#----------------------------------------------------------------# def Sphere(n): @@ -151,14 +182,17 @@ def EilenbergMacLaneSpace(G, n): sage: [f3.homology(i) for i in range(8)] # optional - kenzo [Z, 0, 0, C2, 0, C2, C2, C2] """ - if G is ZZ: + if G == ZZ: kenzospace = k_z(n) return KenzoSimplicialGroup(kenzospace) - elif G in CommutativeAdditiveGroups() and G.cardinality() == 2: + elif G == AdditiveAbelianGroup([2]): kenzospace = k_z2(n) return KenzoSimplicialGroup(kenzospace) + elif G in CommutativeAdditiveGroups() and G.is_cyclic(): + kenzospace = k_zp(G.cardinality(), n) + return KenzoSimplicialGroup(kenzospace) else: - raise NotImplementedError("Eilenberg-MacLane spaces are only supported over ZZ and ZZ_2") + raise NotImplementedError("Eilenberg-MacLane spaces are only supported over ZZ and ZZ_n") class KenzoObject(SageObject): @@ -244,6 +278,7 @@ def homology(self, n): res.append(pair[0].python()) return HomologyGroup(len(res), ZZ, res) + def tensor_product(self, other): r""" Return the tensor product of ``self`` and ``other``. @@ -268,6 +303,79 @@ def tensor_product(self, other): return KenzoChainComplex(tnsr_prdc(self._kenzo, other._kenzo)) + def basis(self, dim): + r""" + Return the list of generators of the Kenzo chain complex ``self`` in dimension ``dim``. + + INPUT: + + - ``dim``- An integer number + + OUTPUT: + + - A list of the form ['G"dim"G0', 'G"dim"G1', 'G"dim"G2', ...]. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + [K1 Chain-Complex] + sage: for i in range(6): # optional - kenzo + print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) # optional - kenzo + Basis in dimension 0: ['G0G0', 'G0G1', 'G0G2'] + Basis in dimension 1: ['G1G0', 'G1G1'] + Basis in dimension 2: None + Basis in dimension 3: ['G3G0', 'G3G1'] + Basis in dimension 4: ['G4G0', 'G4G1'] + Basis in dimension 5: ['G5G0', 'G5G1', 'G5G2'] + + """ + return basis_aux1(self._kenzo, dim).python() + + + def dffr(self, dim, comb): + r""" + Return the differential of a combination. + + INPUT: + - ``dim``- An integer number + - ``comb``- A list representing a formal sum of generators in the module of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the generators must be in ascending order respect to the number after the second G in their representation; the parameter ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in Kenzo. + + OUTPUT: + + - A Kenzo combination representing the differential of the formal combination represented by ``comb`` in the chain complex ``self`` in dimension ``dim``. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + [K1 Chain-Complex] + sage: kenzo_chcm.basis(4) # optional - kenzo + ['G4G0', 'G4G1'] + sage: kenzo_chcm.dffr(4, [1, 'G4G0']) # optional - kenzo + {CMBN 3} <1 * G3G0> <3 * G3G1> + sage: kenzo_chcm.basis(5) # optional - kenzo + ['G5G0', 'G5G1', 'G5G2'] + sage: kenzo_chcm.dffr(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + {CMBN 4} <6 * G4G0> <-3 * G4G1> + + """ + cmbn_list = pairing(comb) + return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) + + + def orgn(self): + return str(orgn_aux1(self._kenzo)) + + class KenzoSimplicialSet(KenzoChainComplex): r""" Wrapper to Kenzo simplicial sets. @@ -346,6 +454,28 @@ def suspension(self): return KenzoSimplicialSet(suspension(self._kenzo)) + def homotopy_group(self, n): + """ + Return the n'th homotopy group of ``self`` + INPUT: + - ``n`` - the dimension of the homotopy group to be computed + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: p = s2.cartesian_product(s2) # optional - kenzo + sage: p.homotopy_group(3) # optional - kenzo + Multiplicative Abelian group isomorphic to Z x Z + """ + if not n in ZZ or n < 2: + raise ValueError("homotopy groups can only be computed for dimensions greater than 1") + lgens = homotopy_list(self._kenzo, n).python() + if lgens != None : + trgens = [0 if i == 1 else i for i in sorted(lgens)] + return AbelianGroup(trgens) + else: + return AbelianGroup([]) + + class KenzoSimplicialGroup(KenzoSimplicialSet): r""" Wrapper around Kenzo simplicial groups. @@ -371,3 +501,280 @@ def classifying_space(self): [Z, 0, 0, 0, C2, 0, 0, 0] """ return KenzoSimplicialGroup(classifying_space(self._kenzo)) + + +#----------------------------------------------------------------# + + +def k2s_matrix(kmatrix): + r"""Convert an array of ECL to a matrix of Sage. + """ + dimensions = array_dimensions(kmatrix).python() + kmatrix_list = make_array_to_lists(kmatrix).python() + return matrix(dimensions[0], dimensions[1], kmatrix_list) + + +def s2k_matrix(smatrix): + r"""Convert a matrix of Sage to an array of ECL. + """ + initcontents = [] + dimensions = smatrix.dimensions() + for i in smatrix.rows(): + initcontents.append(i.list()) + return make_array_from_lists(dimensions[0], dimensions[1], initcontents) + + +def s2k_dictmat(sdictmat): + r"""Convert a dictionary in Sage, whose values are matrices, to an assoc list in ECL. + """ + rslt = EclObject([]) + for k in sdictmat.keys(): + rslt = EclObject(k).cons(s2k_matrix(sdictmat[k])).cons(rslt) + return rslt + + +def pairing(slist): + r"""Convert a list of Sage (which has an even length) to an assoc list in ECL. + """ + rslt = EclObject([]) + for k in range(len(slist) - 1, 0, -2): + rslt = EclObject(slist[k - 1]).cons(EclObject(slist[k])).cons(rslt) + return rslt + + +def KChainComplex(schcm): + r"""Construct a KenzoChainComplex from a ChainComplex of degree = -1 in Sage. + + INPUT: + + - ``schcm`` - A ChainComplex of degree = -1 + + OUTPUT: + + - A KenzoChainComplex + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + [K1 Chain-Complex] + sage: kenzo_chcm.homology(5) # optional - kenzo + Z x Z + + """ + + chcm = s2k_dictmat(schcm.differential()) + str_orgn = str(schcm.differential())[1:-1].replace(":"," ").replace(" ",".").replace("\n","").replace(",","") + return KenzoChainComplex(kchaincomplex_aux1(chcm, str_orgn)) + + +def SChainComplex (kchcm, start = 0, end = 15): + r""" + Convert the KenzoChainComplex ``kchcm`` (between dimensions ``start`` and ``end``) to a ChainComplex. + + INPUT: + + - ``kchcm``- A KenzoChainComplex + - ``start``- An integer number (optional, default 0) + - ``end``- An integer number greater than or equal to ``start`` (optional, default 15) + OUTPUT: + + - A ChainComplex + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KChainComplex, SChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: SChainComplex(KChainComplex(sage_chcm)) == sage_chcm # optional - kenzo + True + """ + + matrices = {} + for i in range(start, end): + dffr_i = chcm_mat2(kchcm._kenzo, i) + if ((nlig(dffr_i).python() != 0) and (ncol(dffr_i).python() != 0)) == True: + matrices[i] = k2s_matrix(convertmatrice(dffr_i)) + return ChainComplex(matrices, degree = -1) + + +#----------------------------------------------------------------# + + +def SAbstractSimplex(KAbSm, dim): + r"""Convert an abstract simplex of Kenzo to an AbstractSimplex. + INPUT: + + - ``KAbSm``- An abstract simplex of Kenzo. + - ``dim``- The dimension of ``KAbSm``. + OUTPUT: + + - An AbstractSimplex. + EXAMPLES:: + + sage: from sage.interfaces.kenzo import SAbstractSimplex # optional - kenzo + sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo + sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo + sage: SAbSm1.degeneracies() + [3, 2, 1, 0] + sage: SAbSm1.dimension() + 6 + sage: SAbSm2.dimension() + 11 + """ + degeneracies = dgop_int_ext(dgop(KAbSm._kenzo)).python() + if degeneracies == None: + degeneracies = [] + else: + degeneracies = tuple(degeneracies) + name = gmsm(KAbSm._kenzo).python() + return AbstractSimplex(dim, degeneracies, name = name) + + +def KAbstractSimplex(SAbSm): + r"""Convert an AbstractSimplex in Sage to an abstract simplex of Kenzo. + INPUT: + + - ``SAbSm``- An AbstractSimplex. + OUTPUT: + + - An abstract simplex of Kenzo. + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KAbstractSimplex, SAbstractSimplex # optional - kenzo + sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') + sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo + sage: SAbSm.degeneracies() == SAbSm2.degeneracies() + True + sage: SAbSm.dimension() == SAbSm2.dimension() + True + """ + return KenzoObject(kabstractsimplex_aux1(SAbSm.degeneracies(), str(SAbSm))) + + +def KFiniteSimplicialSet(ssimpset): + r"""Convert a finite SimplicialSet in Sage to a finite simplicial set of Kenzo. + INPUT: + + - ``ssimpset``- A finite SimplicialSet. + OUTPUT: + + - A finite simplicial set of Kenzo. + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KFiniteSimplicialSet # optional - kenzo + sage: s0 = AbstractSimplex(0, name='s0') + sage: s1 = AbstractSimplex(0, name='s1') + sage: s2 = AbstractSimplex(0, name='s2') + sage: s01 = AbstractSimplex(1, name='s01') + sage: s02 = AbstractSimplex(1, name='s02') + sage: s12 = AbstractSimplex(1, name='s12') + sage: s012 = AbstractSimplex(2, name='s012') + sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) + sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo + sage: KTriangle.homology(1) # optional - kenzo + Z + sage: S1 = simplicial_sets.Sphere(1) + sage: S3 = simplicial_sets.Sphere(3) + sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo + sage: KS1vS3.homology(3) # optional - kenzo + Z + """ + + if hasattr(ssimpset, 'factors') and str(ssimpset)[0:5] != 'Wedge': + return KFiniteSimplicialSet(ssimpset.factor(0)).cartesian_product(KFiniteSimplicialSet(ssimpset.factor(1))) + else: + dim = ssimpset.dimension() + list_rslt = [str(i) for i in ssimpset.n_cells(0)] + if (dim > 0): + for k in range(1, dim + 1): + k_cells = ssimpset.n_cells(k) + if (len(k_cells) > 0): + list_rslt.append(k) + for x in k_cells: + list_rslt.append(str(x)) + auxiliar_list = [] + for z in ssimpset.faces(x): + degen_z = z.degeneracies() + name = str(z.nondegenerate()) + degen_z.append(name) + auxiliar_list.append(degen_z) + list_rslt.append(auxiliar_list) + return KenzoSimplicialSet(build_finite_ss2(list_rslt)) + + +def SFiniteSimplicialSet(ksimpset, limit): + r"""Convert the ``limit``-skeleton of a finite simplicial set in Kenzo to a finite SimplicialSet in Sage. + INPUT: + + - ``ksimpset``- A finite simplicial set in Kenzo. + - ``limit``- A natural number. + OUTPUT: + + - A finite SimplicialSet. + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo + sage: s0 = AbstractSimplex(0, name='s0') + sage: s1 = AbstractSimplex(0, name='s1') + sage: s2 = AbstractSimplex(0, name='s2') + sage: s01 = AbstractSimplex(1, name='s01') + sage: s02 = AbstractSimplex(1, name='s02') + sage: s12 = AbstractSimplex(1, name='s12') + sage: s012 = AbstractSimplex(2, name='s012') + sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) + sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo + sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo + sage: STriangle.homology() + {0: 0, 1: Z} + sage: S1 = simplicial_sets.Sphere(1) + sage: S3 = simplicial_sets.Sphere(3) + sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo + sage: SS1vS3 = SFiniteSimplicialSet(KS1vS3, 3) # optional - kenzo + sage: SS1vS3.homology() + {0: 0, 1: Z, 2: 0, 3: Z} + """ + + list_orgn = orgn_aux1(ksimpset._kenzo).python() + if nth(0, list_orgn).python()[0] == 'CRTS-PRDC': + return SFiniteSimplicialSet(KenzoSimplicialSet(nth(1, list_orgn)), limit).cartesian_product(SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) + rslt = {} + simplices = [] + faces = [] + bases = [] + names = [] + for k in range(limit + 1): + basis_k = basis_aux1(ksimpset._kenzo, k) + names_k = ksimpset.basis(k) + lbasis_k = [AbstractSimplex(k, name = i) for i in EclListIterator(basis_k)] + bases.append(lbasis_k) + names.append(names_k) + all_simplices = sfinitesimplicialset_aux1(ksimpset._kenzo, limit) + lall_simplices = [i for i in EclListIterator(all_simplices)] + dim = 1 + for Kdim in lall_simplices: + for simp in Kdim: + index1 = names[dim].index(str(simp.car())) + lKdim_cdr = [] + for i in EclListIterator(simp.cdr()): + degenop = dgop_int_ext(dgop(i)).python() + if degenop == None: + degenop = [] + index2 = names[dim - len(degenop) - 1].index(str(gmsm(i))) + lKdim_cdr.append(bases[dim - len(degenop) - 1][index2].apply_degeneracies(*degenop)) + simplices.append(bases[dim][index1]) + faces.append(tuple(lKdim_cdr)) + dim += 1 + for i in range(len(simplices)): + rslt[simplices[i]] = faces[i] + return SimplicialSet(rslt) + + + From e1daeb1e157b7ba205aff4c296d8f6a24066229b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Cuevas-Rozo?= Date: Wed, 29 May 2019 14:22:18 +0200 Subject: [PATCH 270/476] Methods for computing on finite simplicial sets and chain complexes added. Homotopy added. --- src/sage/interfaces/kenzo.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index a38215e4e38..05bb2b3de04 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -584,6 +584,7 @@ def SChainComplex (kchcm, start = 0, end = 15): OUTPUT: - A ChainComplex + EXAMPLES:: sage: from sage.interfaces.kenzo import KChainComplex, SChainComplex # optional - kenzo @@ -615,6 +616,7 @@ def SAbstractSimplex(KAbSm, dim): OUTPUT: - An AbstractSimplex. + EXAMPLES:: sage: from sage.interfaces.kenzo import SAbstractSimplex # optional - kenzo @@ -645,6 +647,7 @@ def KAbstractSimplex(SAbSm): OUTPUT: - An abstract simplex of Kenzo. + EXAMPLES:: sage: from sage.interfaces.kenzo import KAbstractSimplex, SAbstractSimplex # optional - kenzo @@ -667,6 +670,7 @@ def KFiniteSimplicialSet(ssimpset): OUTPUT: - A finite simplicial set of Kenzo. + EXAMPLES:: sage: from sage.interfaces.kenzo import KFiniteSimplicialSet # optional - kenzo @@ -719,6 +723,7 @@ def SFiniteSimplicialSet(ksimpset, limit): OUTPUT: - A finite SimplicialSet. + EXAMPLES:: sage: from sage.interfaces.kenzo import KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo From 88fc95d8c2708ff7beff13a954f2ee5fca1922ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Cuevas-Rozo?= Date: Fri, 31 May 2019 12:30:49 +0200 Subject: [PATCH 271/476] Homotopy added. Simplicial sets and chain complexes added. --- src/sage/interfaces/kenzo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 05bb2b3de04..3fdb2a60fa0 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -783,3 +783,5 @@ def SFiniteSimplicialSet(ksimpset, limit): + + From 259834476ef99c656abf6a068178fbd324094ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Cuevas-Rozo?= Date: Mon, 3 Jun 2019 16:32:57 +0200 Subject: [PATCH 272/476] Homotopy groups added. Chain complexes and simplicial sets functions added. --- src/sage/interfaces/kenzo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 3fdb2a60fa0..bfec873c3c8 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -785,3 +785,6 @@ def SFiniteSimplicialSet(ksimpset, limit): + + + From d8f814c4551160b6877f859e269312e36e4dc195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Cuevas-Rozo?= Date: Tue, 4 Jun 2019 23:14:18 +0200 Subject: [PATCH 273/476] Auxiliary functions for Homotopy groups, Chain complexes and Simplicial sets added. --- src/sage/interfaces/kenzo.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index bfec873c3c8..3fdb2a60fa0 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -785,6 +785,3 @@ def SFiniteSimplicialSet(ksimpset, limit): - - - From be3f5202f38cc3d0766705ab8e4b2165b0e21b8a Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 7 Jun 2019 15:03:19 +0200 Subject: [PATCH 274/476] Fixed style, and some failing doctests --- src/sage/interfaces/kenzo.py | 261 +++++++++++++++++++---------------- 1 file changed, 145 insertions(+), 116 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 3fdb2a60fa0..68ba2412f27 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -29,6 +29,8 @@ from sage.structure.sage_object import SageObject from sage.homology.homology_group import HomologyGroup from sage.rings.integer_ring import ZZ +from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup +from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from sage.matrix.all import matrix @@ -93,9 +95,6 @@ sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") -#----------------------------------------------------------------# - - def Sphere(n): r""" Return the ``n`` dimensional sphere as a Kenzo simplicial set. @@ -278,7 +277,6 @@ def homology(self, n): res.append(pair[0].python()) return HomologyGroup(len(res), ZZ, res) - def tensor_product(self, other): r""" Return the tensor product of ``self`` and ``other``. @@ -302,76 +300,92 @@ def tensor_product(self, other): """ return KenzoChainComplex(tnsr_prdc(self._kenzo, other._kenzo)) - def basis(self, dim): r""" Return the list of generators of the Kenzo chain complex ``self`` in dimension ``dim``. - + INPUT: - + - ``dim``- An integer number - + OUTPUT: - + - A list of the form ['G"dim"G0', 'G"dim"G1', 'G"dim"G2', ...]. - + EXAMPLES:: - + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K589 Chain-Complex] sage: for i in range(6): # optional - kenzo - print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) # optional - kenzo + ....: print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) # optional - kenzo Basis in dimension 0: ['G0G0', 'G0G1', 'G0G2'] Basis in dimension 1: ['G1G0', 'G1G1'] Basis in dimension 2: None Basis in dimension 3: ['G3G0', 'G3G1'] Basis in dimension 4: ['G4G0', 'G4G1'] - Basis in dimension 5: ['G5G0', 'G5G1', 'G5G2'] - + Basis in dimension 5: ['G5G0', 'G5G1', 'G5G2'] + """ return basis_aux1(self._kenzo, dim).python() - - + def dffr(self, dim, comb): r""" Return the differential of a combination. - + INPUT: + - ``dim``- An integer number - - ``comb``- A list representing a formal sum of generators in the module of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the generators must be in ascending order respect to the number after the second G in their representation; the parameter ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in Kenzo. - + + - ``comb``- A list representing a formal sum of generators in the module + of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 + we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the + generators must be in ascending order respect to the number after the + second G in their representation; the parameter + ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in + Kenzo. + OUTPUT: - + - A Kenzo combination representing the differential of the formal combination represented by ``comb`` in the chain complex ``self`` in dimension ``dim``. - + EXAMPLES:: - + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: kenzo_chcm.dffr(4, [1, 'G4G0']) # optional - kenzo - {CMBN 3} <1 * G3G0> <3 * G3G1> + + ----------------------------------------------------------------------{CMBN 3} + <1 * G3G0> + <3 * G3G1> + ------------------------------------------------------------------------------ + sage: kenzo_chcm.basis(5) # optional - kenzo ['G5G0', 'G5G1', 'G5G2'] sage: kenzo_chcm.dffr(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo - {CMBN 4} <6 * G4G0> <-3 * G4G1> - + + ----------------------------------------------------------------------{CMBN 4} + <6 * G4G0> + <-3 * G4G1> + ------------------------------------------------------------------------------ + """ cmbn_list = pairing(comb) return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) - def orgn(self): return str(orgn_aux1(self._kenzo)) @@ -453,7 +467,6 @@ def suspension(self): """ return KenzoSimplicialSet(suspension(self._kenzo)) - def homotopy_group(self, n): """ Return the n'th homotopy group of ``self`` @@ -466,13 +479,13 @@ def homotopy_group(self, n): sage: p.homotopy_group(3) # optional - kenzo Multiplicative Abelian group isomorphic to Z x Z """ - if not n in ZZ or n < 2: + if n not in ZZ or n < 2: raise ValueError("homotopy groups can only be computed for dimensions greater than 1") lgens = homotopy_list(self._kenzo, n).python() - if lgens != None : + if lgens is not None: trgens = [0 if i == 1 else i for i in sorted(lgens)] return AbelianGroup(trgens) - else: + else: return AbelianGroup([]) @@ -503,11 +516,9 @@ def classifying_space(self): return KenzoSimplicialGroup(classifying_space(self._kenzo)) -#----------------------------------------------------------------# - - def k2s_matrix(kmatrix): - r"""Convert an array of ECL to a matrix of Sage. + r""" + Convert an array of ECL to a matrix of Sage. """ dimensions = array_dimensions(kmatrix).python() kmatrix_list = make_array_to_lists(kmatrix).python() @@ -515,7 +526,8 @@ def k2s_matrix(kmatrix): def s2k_matrix(smatrix): - r"""Convert a matrix of Sage to an array of ECL. + r""" + Convert a matrix of Sage to an array of ECL. """ initcontents = [] dimensions = smatrix.dimensions() @@ -525,7 +537,9 @@ def s2k_matrix(smatrix): def s2k_dictmat(sdictmat): - r"""Convert a dictionary in Sage, whose values are matrices, to an assoc list in ECL. + r""" + Convert a dictionary in Sage, whose values are matrices, to an assoc list + in ECL. """ rslt = EclObject([]) for k in sdictmat.keys(): @@ -534,7 +548,8 @@ def s2k_dictmat(sdictmat): def pairing(slist): - r"""Convert a list of Sage (which has an even length) to an assoc list in ECL. + r""" + Convert a list of Sage (which has an even length) to an assoc list in ECL. """ rslt = EclObject([]) for k in range(len(slist) - 1, 0, -2): @@ -543,50 +558,55 @@ def pairing(slist): def KChainComplex(schcm): - r"""Construct a KenzoChainComplex from a ChainComplex of degree = -1 in Sage. - + r""" + Construct a KenzoChainComplex from a ChainComplex of degree = -1 in + Sage. + INPUT: - - - ``schcm`` - A ChainComplex of degree = -1 - + + - ``schcm`` - A ChainComplex of degree = -1 + OUTPUT: - + - A KenzoChainComplex - + EXAMPLES:: - + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: kenzo_chcm.homology(5) # optional - kenzo Z x Z - """ - chcm = s2k_dictmat(schcm.differential()) - str_orgn = str(schcm.differential())[1:-1].replace(":"," ").replace(" ",".").replace("\n","").replace(",","") + str_orgn = str(schcm.differential())[1:-1].replace(":", " ").replace(" ", ".").replace("\n", "").replace(",", "") return KenzoChainComplex(kchaincomplex_aux1(chcm, str_orgn)) -def SChainComplex (kchcm, start = 0, end = 15): +def SChainComplex(kchcm, start=0, end=15): r""" - Convert the KenzoChainComplex ``kchcm`` (between dimensions ``start`` and ``end``) to a ChainComplex. - + Convert the KenzoChainComplex ``kchcm`` (between dimensions ``start`` and + ``end``) to a ChainComplex. + INPUT: - + - ``kchcm``- A KenzoChainComplex + - ``start``- An integer number (optional, default 0) + - ``end``- An integer number greater than or equal to ``start`` (optional, default 15) + OUTPUT: - - - A ChainComplex + + - A ChainComplex EXAMPLES:: - + sage: from sage.interfaces.kenzo import KChainComplex, SChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -599,80 +619,87 @@ def SChainComplex (kchcm, start = 0, end = 15): matrices = {} for i in range(start, end): dffr_i = chcm_mat2(kchcm._kenzo, i) - if ((nlig(dffr_i).python() != 0) and (ncol(dffr_i).python() != 0)) == True: + if ((nlig(dffr_i).python() != 0) and (ncol(dffr_i).python() != 0)): matrices[i] = k2s_matrix(convertmatrice(dffr_i)) - return ChainComplex(matrices, degree = -1) - - -#----------------------------------------------------------------# + return ChainComplex(matrices, degree=-1) def SAbstractSimplex(KAbSm, dim): - r"""Convert an abstract simplex of Kenzo to an AbstractSimplex. + r""" + Convert an abstract simplex of Kenzo to an AbstractSimplex. INPUT: - + - ``KAbSm``- An abstract simplex of Kenzo. + - ``dim``- The dimension of ``KAbSm``. + OUTPUT: - + - An AbstractSimplex. EXAMPLES:: - - sage: from sage.interfaces.kenzo import SAbstractSimplex # optional - kenzo - sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo - sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo - sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo - sage: SAbSm1.degeneracies() + + sage: from sage.libs.ecl import EclObject, ecl_eval + sage: from sage.interfaces.kenzo import KenzoObject, SAbstractSimplex # optional - kenzo + sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo + sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo + sage: SAbSm1.degeneracies() # optional - kenzo [3, 2, 1, 0] - sage: SAbSm1.dimension() + sage: SAbSm1.dimension() # optional - kenzo 6 - sage: SAbSm2.dimension() + sage: SAbSm2.dimension() # optional - kenzo 11 """ degeneracies = dgop_int_ext(dgop(KAbSm._kenzo)).python() - if degeneracies == None: + if degeneracies is None: degeneracies = [] else: degeneracies = tuple(degeneracies) name = gmsm(KAbSm._kenzo).python() - return AbstractSimplex(dim, degeneracies, name = name) + return AbstractSimplex(dim, degeneracies, name=name) def KAbstractSimplex(SAbSm): - r"""Convert an AbstractSimplex in Sage to an abstract simplex of Kenzo. + r""" + Convert an AbstractSimplex in Sage to an abstract simplex of Kenzo. INPUT: - + - ``SAbSm``- An AbstractSimplex. + OUTPUT: - + - An abstract simplex of Kenzo. EXAMPLES:: - - sage: from sage.interfaces.kenzo import KAbstractSimplex, SAbstractSimplex # optional - kenzo - sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') - sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo - sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo - sage: SAbSm.degeneracies() == SAbSm2.degeneracies() + + sage: from sage.interfaces.kenzo import AbstractSimplex, KAbstractSimplex, SAbstractSimplex # optional - kenzo + sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo + sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo + sage: SAbSm.degeneracies() == SAbSm2.degeneracies() # optional - kenzo True - sage: SAbSm.dimension() == SAbSm2.dimension() + sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ return KenzoObject(kabstractsimplex_aux1(SAbSm.degeneracies(), str(SAbSm))) def KFiniteSimplicialSet(ssimpset): - r"""Convert a finite SimplicialSet in Sage to a finite simplicial set of Kenzo. + r""" + Convert a finite SimplicialSet in Sage to a finite simplicial set of Kenzo. + INPUT: - + - ``ssimpset``- A finite SimplicialSet. + OUTPUT: - + - A finite simplicial set of Kenzo. EXAMPLES:: - + + sage: from sage.homology.simplicial_set import AbstractSimplex, SimplicialSet sage: from sage.interfaces.kenzo import KFiniteSimplicialSet # optional - kenzo sage: s0 = AbstractSimplex(0, name='s0') sage: s1 = AbstractSimplex(0, name='s1') @@ -715,41 +742,48 @@ def KFiniteSimplicialSet(ssimpset): def SFiniteSimplicialSet(ksimpset, limit): - r"""Convert the ``limit``-skeleton of a finite simplicial set in Kenzo to a finite SimplicialSet in Sage. + r"""Convert the ``limit``-skeleton of a finite simplicial set in Kenzo to a + finite SimplicialSet in Sage. + INPUT: - + - ``ksimpset``- A finite simplicial set in Kenzo. + - ``limit``- A natural number. + OUTPUT: - + - A finite SimplicialSet. EXAMPLES:: - - sage: from sage.interfaces.kenzo import KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo - sage: s0 = AbstractSimplex(0, name='s0') - sage: s1 = AbstractSimplex(0, name='s1') - sage: s2 = AbstractSimplex(0, name='s2') - sage: s01 = AbstractSimplex(1, name='s01') - sage: s02 = AbstractSimplex(1, name='s02') - sage: s12 = AbstractSimplex(1, name='s12') - sage: s012 = AbstractSimplex(2, name='s012') + + sage: from sage.homology.simplicial_set import SimplicialSet + sage: from sage.interfaces.kenzo import AbstractSimplex, \ + ....: KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo + sage: s0 = AbstractSimplex(0, name='s0') # optional - kenzo + sage: s1 = AbstractSimplex(0, name='s1') # optional - kenzo + sage: s2 = AbstractSimplex(0, name='s2') # optional - kenzo + sage: s01 = AbstractSimplex(1, name='s01') # optional - kenzo + sage: s02 = AbstractSimplex(1, name='s02') # optional - kenzo + sage: s12 = AbstractSimplex(1, name='s12') # optional - kenzo + sage: s012 = AbstractSimplex(2, name='s012') # optional - kenzo sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) - sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo - sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo - sage: STriangle.homology() + sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo + sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo + sage: STriangle.homology() # optional - kenzo {0: 0, 1: Z} sage: S1 = simplicial_sets.Sphere(1) sage: S3 = simplicial_sets.Sphere(3) - sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo - sage: SS1vS3 = SFiniteSimplicialSet(KS1vS3, 3) # optional - kenzo - sage: SS1vS3.homology() + sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo + sage: SS1vS3 = SFiniteSimplicialSet(KS1vS3, 3) # optional - kenzo + sage: SS1vS3.homology() # optional - kenzo {0: 0, 1: Z, 2: 0, 3: Z} """ list_orgn = orgn_aux1(ksimpset._kenzo).python() if nth(0, list_orgn).python()[0] == 'CRTS-PRDC': - return SFiniteSimplicialSet(KenzoSimplicialSet(nth(1, list_orgn)), limit).cartesian_product(SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) + return SFiniteSimplicialSet(KenzoSimplicialSet(nth(1, list_orgn)), + limit).cartesian_product(SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) rslt = {} simplices = [] faces = [] @@ -758,7 +792,7 @@ def SFiniteSimplicialSet(ksimpset, limit): for k in range(limit + 1): basis_k = basis_aux1(ksimpset._kenzo, k) names_k = ksimpset.basis(k) - lbasis_k = [AbstractSimplex(k, name = i) for i in EclListIterator(basis_k)] + lbasis_k = [AbstractSimplex(k, name=i) for i in EclListIterator(basis_k)] bases.append(lbasis_k) names.append(names_k) all_simplices = sfinitesimplicialset_aux1(ksimpset._kenzo, limit) @@ -770,7 +804,7 @@ def SFiniteSimplicialSet(ksimpset, limit): lKdim_cdr = [] for i in EclListIterator(simp.cdr()): degenop = dgop_int_ext(dgop(i)).python() - if degenop == None: + if degenop is None: degenop = [] index2 = names[dim - len(degenop) - 1].index(str(gmsm(i))) lKdim_cdr.append(bases[dim - len(degenop) - 1][index2].apply_degeneracies(*degenop)) @@ -780,8 +814,3 @@ def SFiniteSimplicialSet(ksimpset, limit): for i in range(len(simplices)): rslt[simplices[i]] = faces[i] return SimplicialSet(rslt) - - - - - From 31385be3a71e292d182c86180fb782f3718b83c5 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 24 Jun 2019 14:12:57 +0200 Subject: [PATCH 275/476] some style improvements, and identify simplicies by hash --- src/sage/interfaces/kenzo.py | 71 ++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 68ba2412f27..1e105dd11be 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -334,7 +334,7 @@ def basis(self, dim): """ return basis_aux1(self._kenzo, dim).python() - def dffr(self, dim, comb): + def differential(self, dim, comb): r""" Return the differential of a combination. @@ -352,7 +352,9 @@ def dffr(self, dim, comb): OUTPUT: - - A Kenzo combination representing the differential of the formal combination represented by ``comb`` in the chain complex ``self`` in dimension ``dim``. + - A Kenzo combination representing the differential of the formal + combination represented by ``comb`` in the chain complex ``self`` in + dimension ``dim``. EXAMPLES:: @@ -366,7 +368,7 @@ def dffr(self, dim, comb): [K... Chain-Complex] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] - sage: kenzo_chcm.dffr(4, [1, 'G4G0']) # optional - kenzo + sage: kenzo_chcm.differential(4, [1, 'G4G0']) # optional - kenzo ----------------------------------------------------------------------{CMBN 3} <1 * G3G0> @@ -375,7 +377,7 @@ def dffr(self, dim, comb): sage: kenzo_chcm.basis(5) # optional - kenzo ['G5G0', 'G5G1', 'G5G2'] - sage: kenzo_chcm.dffr(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + sage: kenzo_chcm.differential(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo ----------------------------------------------------------------------{CMBN 4} <6 * G4G0> @@ -557,14 +559,14 @@ def pairing(slist): return rslt -def KChainComplex(schcm): +def KChainComplex(chain_complex): r""" Construct a KenzoChainComplex from a ChainComplex of degree = -1 in Sage. INPUT: - - ``schcm`` - A ChainComplex of degree = -1 + - ``chain_complex`` - A ChainComplex of degree = -1 OUTPUT: @@ -583,19 +585,20 @@ def KChainComplex(schcm): sage: kenzo_chcm.homology(5) # optional - kenzo Z x Z """ - chcm = s2k_dictmat(schcm.differential()) - str_orgn = str(schcm.differential())[1:-1].replace(":", " ").replace(" ", ".").replace("\n", "").replace(",", "") + d = chain_complex.differential() + chcm = s2k_dictmat(d) + str_orgn = str(d)[1:-1].replace(":", " ").replace(" ", ".").replace("\n", "").replace(",", "") return KenzoChainComplex(kchaincomplex_aux1(chcm, str_orgn)) -def SChainComplex(kchcm, start=0, end=15): +def SChainComplex(kchaincomplex, start=0, end=15): r""" Convert the KenzoChainComplex ``kchcm`` (between dimensions ``start`` and ``end``) to a ChainComplex. INPUT: - - ``kchcm``- A KenzoChainComplex + - ``kchaincomplex``- A KenzoChainComplex - ``start``- An integer number (optional, default 0) @@ -618,20 +621,20 @@ def SChainComplex(kchcm, start=0, end=15): matrices = {} for i in range(start, end): - dffr_i = chcm_mat2(kchcm._kenzo, i) + dffr_i = chcm_mat2(kchaincomplex._kenzo, i) if ((nlig(dffr_i).python() != 0) and (ncol(dffr_i).python() != 0)): matrices[i] = k2s_matrix(convertmatrice(dffr_i)) return ChainComplex(matrices, degree=-1) -def SAbstractSimplex(KAbSm, dim): +def SAbstractSimplex(simplex, dim): r""" Convert an abstract simplex of Kenzo to an AbstractSimplex. INPUT: - - ``KAbSm``- An abstract simplex of Kenzo. + - ``simplex``- An abstract simplex of Kenzo. - - ``dim``- The dimension of ``KAbSm``. + - ``dim``- The dimension of ``simplex``. OUTPUT: @@ -651,21 +654,21 @@ def SAbstractSimplex(KAbSm, dim): sage: SAbSm2.dimension() # optional - kenzo 11 """ - degeneracies = dgop_int_ext(dgop(KAbSm._kenzo)).python() + degeneracies = dgop_int_ext(dgop(simplex._kenzo)).python() if degeneracies is None: degeneracies = [] else: degeneracies = tuple(degeneracies) - name = gmsm(KAbSm._kenzo).python() + name = gmsm(simplex._kenzo).python() return AbstractSimplex(dim, degeneracies, name=name) -def KAbstractSimplex(SAbSm): +def KAbstractSimplex(simplex): r""" Convert an AbstractSimplex in Sage to an abstract simplex of Kenzo. INPUT: - - ``SAbSm``- An AbstractSimplex. + - ``simplex``- An AbstractSimplex. OUTPUT: @@ -673,16 +676,17 @@ def KAbstractSimplex(SAbSm): EXAMPLES:: - sage: from sage.interfaces.kenzo import AbstractSimplex, KAbstractSimplex, SAbstractSimplex # optional - kenzo - sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo - sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo - sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo - sage: SAbSm.degeneracies() == SAbSm2.degeneracies() # optional - kenzo + sage: from sage.homology.simplicial_set import AbstractSimplex + sage: from sage.interfaces.kenzo import KAbstractSimplex, SAbstractSimplex # optional - kenzo + sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo + sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo + sage: SAbSm.degeneracies() == SAbSm2.degeneracies() # optional - kenzo True - sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo + sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ - return KenzoObject(kabstractsimplex_aux1(SAbSm.degeneracies(), str(SAbSm))) + return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), 's'+str(hash(simplex)))) def KFiniteSimplicialSet(ssimpset): @@ -718,23 +722,26 @@ def KFiniteSimplicialSet(ssimpset): sage: KS1vS3.homology(3) # optional - kenzo Z """ - - if hasattr(ssimpset, 'factors') and str(ssimpset)[0:5] != 'Wedge': - return KFiniteSimplicialSet(ssimpset.factor(0)).cartesian_product(KFiniteSimplicialSet(ssimpset.factor(1))) + from sage.homology.simplicial_set_constructions import ProductOfSimplicialSets + if isinstance(ssimpset, ProductOfSimplicialSets): + f0 = KFiniteSimplicialSet(ssimpset.factor(0)) + for f1 in ssimpset.factors()[1:]: + f0 = f0.cartesian_product(KFiniteSimplicialSet(f1)) + return f0 else: dim = ssimpset.dimension() - list_rslt = [str(i) for i in ssimpset.n_cells(0)] + list_rslt = ['s'+str(hash(i)) for i in ssimpset.n_cells(0)] if (dim > 0): for k in range(1, dim + 1): k_cells = ssimpset.n_cells(k) - if (len(k_cells) > 0): + if k_cells: list_rslt.append(k) for x in k_cells: - list_rslt.append(str(x)) + list_rslt.append('s'+str(hash(x))) auxiliar_list = [] for z in ssimpset.faces(x): degen_z = z.degeneracies() - name = str(z.nondegenerate()) + name = 's'+str(hash(z.nondegenerate())) degen_z.append(name) auxiliar_list.append(degen_z) list_rslt.append(auxiliar_list) From c987078808a2e50cac62b80aa5a6a986eab34bef Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 3 Jul 2019 14:01:27 +0200 Subject: [PATCH 276/476] Use unique meaningul names for cells in KFiniteSimplicialSet --- src/sage/interfaces/kenzo.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 1e105dd11be..b25c67638db 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -618,7 +618,6 @@ def SChainComplex(kchaincomplex, start=0, end=15): sage: SChainComplex(KChainComplex(sage_chcm)) == sage_chcm # optional - kenzo True """ - matrices = {} for i in range(start, end): dffr_i = chcm_mat2(kchaincomplex._kenzo, i) @@ -689,13 +688,13 @@ def KAbstractSimplex(simplex): return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), 's'+str(hash(simplex)))) -def KFiniteSimplicialSet(ssimpset): +def KFiniteSimplicialSet(sset): r""" Convert a finite SimplicialSet in Sage to a finite simplicial set of Kenzo. INPUT: - - ``ssimpset``- A finite SimplicialSet. + - ``sset``- A finite SimplicialSet. OUTPUT: @@ -716,6 +715,8 @@ def KFiniteSimplicialSet(ssimpset): sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo sage: KTriangle.homology(1) # optional - kenzo Z + sage: KTriangle.basis(1) # optional - kenzo + ['CELL_1_0', 'CELL_1_1', 'CELL_1_2'] sage: S1 = simplicial_sets.Sphere(1) sage: S3 = simplicial_sets.Sphere(3) sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo @@ -723,25 +724,27 @@ def KFiniteSimplicialSet(ssimpset): Z """ from sage.homology.simplicial_set_constructions import ProductOfSimplicialSets - if isinstance(ssimpset, ProductOfSimplicialSets): - f0 = KFiniteSimplicialSet(ssimpset.factor(0)) - for f1 in ssimpset.factors()[1:]: + if isinstance(sset, ProductOfSimplicialSets): + f0 = KFiniteSimplicialSet(sset.factor(0)) + for f1 in sset.factors()[1:]: f0 = f0.cartesian_product(KFiniteSimplicialSet(f1)) return f0 else: - dim = ssimpset.dimension() - list_rslt = ['s'+str(hash(i)) for i in ssimpset.n_cells(0)] + allcells = sset.cells() + namecells = {c:'cell_{}_{}'.format(d, allcells[d].index(c)) for d in allcells for c in allcells[d]} + dim = sset.dimension() + list_rslt = [namecells[i] for i in sset.n_cells(0)] if (dim > 0): for k in range(1, dim + 1): - k_cells = ssimpset.n_cells(k) + k_cells = sset.n_cells(k) if k_cells: list_rslt.append(k) for x in k_cells: - list_rslt.append('s'+str(hash(x))) + list_rslt.append(namecells[x]) auxiliar_list = [] - for z in ssimpset.faces(x): + for z in sset.faces(x): degen_z = z.degeneracies() - name = 's'+str(hash(z.nondegenerate())) + name = namecells[z.nondegenerate()] degen_z.append(name) auxiliar_list.append(degen_z) list_rslt.append(auxiliar_list) From d425fb5d9f612a08fa48c9cbfc014d83b5b248e2 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 4 Jul 2019 22:20:29 +0200 Subject: [PATCH 277/476] First implementation of spectral sequences --- src/sage/interfaces/kenzo.py | 95 ++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index b25c67638db..b8afb57a2b3 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -93,6 +93,9 @@ kabstractsimplex_aux1 = EclObject("kabstractsimplex_aux1") kchaincomplex_aux1 = EclObject("kchaincomplex_aux1") sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") +spectral_sequence_group = EclObject("spectral-sequence-group") +spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") +eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") def Sphere(n): @@ -240,6 +243,91 @@ def _repr_(self): kenzo_string = repr(self._kenzo) return kenzo_string[6:-1] +class KenzoSpectralSequence(KenzoObject): + r""" + Wrapper around Kenzo spectral sequences + """ + def group(self, p, i, j): + r""" + Return the ``i,j``'th group of the ``p`` page. + + INPUT: + + - ``p`` -- the page to take the group from. + + - ``i`` -- the column where the group is taken from. + + - ``j`` -- the row where the group is taken from. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere + sage: S2 = Sphere(2) + sage: EMS = S2.em_spectral_sequence() + sage: EMS.group(0, -1, 2) + Additive abelian group isomorphic to Z + sage: EMS.group(0, -1, 3) + Trivial group + """ + invs = spectral_sequence_group(self._kenzo, p, i ,j).python() + if not invs: + invs = [] + return AdditiveAbelianGroup(invs) + def matrix(self, p, i, j): + r""" + Return the matrix that determines the differential from the + ``i,j``'th group of the ``p``'th page. + + INPUT: + + - ``p`` -- the page. + + - ``i`` -- the column of the differential domain. + + - ``j`` -- the row of the differential domain. + """ + return spectral_sequence_differential_matrix(self._kenzo, p, j, j) + def table(self, p, i1, i2, j1, j2): + r""" + Return a table printing the groups in the ``p`` page. + + INPUT: + + - ``p`` -- the page to print. + + -- ``i1`` -- the first column to print. + + -- ``i2`` -- the last column to print. + + -- ``j1`` -- the first row to print. + + -- ``j2`` -- the last row to print. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere + sage: S2 = Sphere(2) + sage: EMS = S2.em_spectral_sequence() + sage: EMS.table(0, -2, 2, -2, 2) + 0 Z 0 0 0 + 0 0 0 0 0 + 0 0 Z 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + """ + from sage.misc.table import table + groups = [] + for j in range(j2-j1+1): + row = [] + for i in range(i1, i2+1): + group = self.group(p,i,j2-j) + if group.invariants(): + row.append(group.short_name()) + else: + row.append('0') + groups.append(row) + return table(groups) + class KenzoChainComplex(KenzoObject): r""" @@ -489,6 +577,13 @@ def homotopy_group(self, n): return AbelianGroup(trgens) else: return AbelianGroup([]) + def em_spectral_sequence(self): + r""" + Return the Eilenberg-Moore spectral sequence of self + """ + if self.homology(1).invariants(): + raise ValueError("Eilenberg-Moore spectral sequence can only be computed from 1-reduced simplicial sets") + return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) class KenzoSimplicialGroup(KenzoSimplicialSet): From 1d801e2515d16dca5c58eb3986783a0aaddfad9e Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 5 Jul 2019 19:33:18 +0200 Subject: [PATCH 278/476] Implemented spectral sequences --- src/sage/interfaces/kenzo.py | 106 +++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index b8afb57a2b3..f1000099c12 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -32,6 +32,7 @@ from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups +from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.matrix.all import matrix from sage.homology.chain_complex import ChainComplex @@ -247,6 +248,7 @@ class KenzoSpectralSequence(KenzoObject): r""" Wrapper around Kenzo spectral sequences """ + def group(self, p, i, j): r""" Return the ``i,j``'th group of the ``p`` page. @@ -261,18 +263,19 @@ def group(self, p, i, j): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere - sage: S2 = Sphere(2) - sage: EMS = S2.em_spectral_sequence() - sage: EMS.group(0, -1, 2) + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo + sage: S2 = Sphere(2) # optional -- kenzo + sage: EMS = S2.em_spectral_sequence() # optional -- kenzo + sage: EMS.group(0, -1, 2) # optional -- kenzo Additive abelian group isomorphic to Z - sage: EMS.group(0, -1, 3) + sage: EMS.group(0, -1, 3) # optional -- kenzo Trivial group """ invs = spectral_sequence_group(self._kenzo, p, i ,j).python() if not invs: invs = [] return AdditiveAbelianGroup(invs) + def matrix(self, p, i, j): r""" Return the matrix that determines the differential from the @@ -285,8 +288,67 @@ def matrix(self, p, i, j): - ``i`` -- the column of the differential domain. - ``j`` -- the row of the differential domain. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo + sage: S3 = Sphere(3) # optional -- kenzo + sage: L = S3.loop_space() # optional -- kenzo + sage: EMS = L.em_spectral_sequence() # optional -- kenzo + sage: EMS.table(1, -5, -2, 5, 8) # optional -- kenzo + 0 Z Z + Z + Z Z + Z + Z + 0 0 0 0 + 0 0 Z Z + Z + 0 0 0 0 + sage: EMS.matrix(1, -2 ,8) # optional -- kenzo + [ 3 3 0] + [-2 0 2] + [ 0 -3 -3] + """ + klist = spectral_sequence_differential_matrix(self._kenzo, p, i, j) + plist = klist.python() + if plist is None or plist==[None]: + i = len(self.group(p, i, j).invariants()) + j = len(self.group(p, i-p, j+p-1).invariants()) + return matrix(i,j) + return matrix(plist) + + def differential(self, p, i, j): + r""" + Return the ``(p, i, j)`` differential morphism of the spectral sequence. + + INPUT: + + - ``p`` -- the page. + + - ``i`` -- the column of the differential domain. + + - ``j`` -- the row of the differential domain. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo + sage: S3 = Sphere(3) # optional -- kenzo + sage: L = S3.loop_space() # optional -- kenzo + sage: EMS = L.em_spectral_sequence() # optional -- kenzo + sage: EMS.table(1,-5,-2,5,8) # optional -- kenzo + 0 Z Z + Z + Z Z + Z + Z + 0 0 0 0 + 0 0 Z Z + Z + 0 0 0 0 + sage: EMS.matrix(1, -3, 8) # optional -- kenzo + [ 2] + [-2] + [ 2] + sage: EMS.differential(1, -3, 8) # optional -- kenzo + Morphism from module over Integer Ring with invariants (0, 0, 0) to module with invariants (0,) that sends the generators to [(2), (-2), (2)] """ - return spectral_sequence_differential_matrix(self._kenzo, p, j, j) + domain = self.group(p, i, j) + codomain = self.group(p, i-p, j+p-1) + M = self.matrix(p, i, j) + images = [codomain(r) for r in M.rows()] + return domain.hom(images, codomain=codomain) + def table(self, p, i1, i2, j1, j2): r""" Return a table printing the groups in the ``p`` page. @@ -305,10 +367,10 @@ def table(self, p, i1, i2, j1, j2): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere - sage: S2 = Sphere(2) - sage: EMS = S2.em_spectral_sequence() - sage: EMS.table(0, -2, 2, -2, 2) + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo + sage: S2 = Sphere(2) # optional -- kenzo + sage: EMS = S2.em_spectral_sequence() # optional -- kenzo + sage: EMS.table(0, -2, 2, -2, 2) # optional -- kenzo 0 Z 0 0 0 0 0 0 0 0 0 0 Z 0 0 @@ -577,12 +639,25 @@ def homotopy_group(self, n): return AbelianGroup(trgens) else: return AbelianGroup([]) + def em_spectral_sequence(self): r""" Return the Eilenberg-Moore spectral sequence of self + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo + sage: S2 = Sphere(2) # optional -- kenzo + sage: EMS = S2.em_spectral_sequence() # optional -- kenzo + sage: EMS.table(0, -2, 2, -2, 2) # optional -- kenzo + 0 Z 0 0 0 + 0 0 0 0 0 + 0 0 Z 0 0 + 0 0 0 0 0 + 0 0 0 0 0 """ if self.homology(1).invariants(): - raise ValueError("Eilenberg-Moore spectral sequence can only be computed from 1-reduced simplicial sets") + raise ValueError("Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets") return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) @@ -863,8 +938,7 @@ def SFiniteSimplicialSet(ksimpset, limit): EXAMPLES:: sage: from sage.homology.simplicial_set import SimplicialSet - sage: from sage.interfaces.kenzo import AbstractSimplex, \ - ....: KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo + sage: from sage.interfaces.kenzo import AbstractSimplex, KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo sage: s0 = AbstractSimplex(0, name='s0') # optional - kenzo sage: s1 = AbstractSimplex(0, name='s1') # optional - kenzo sage: s2 = AbstractSimplex(0, name='s2') # optional - kenzo @@ -872,13 +946,13 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: s02 = AbstractSimplex(1, name='s02') # optional - kenzo sage: s12 = AbstractSimplex(1, name='s12') # optional - kenzo sage: s012 = AbstractSimplex(2, name='s012') # optional - kenzo - sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) + sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) # optional - kenzo sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo sage: STriangle.homology() # optional - kenzo {0: 0, 1: Z} - sage: S1 = simplicial_sets.Sphere(1) - sage: S3 = simplicial_sets.Sphere(3) + sage: S1 = simplicial_sets.Sphere(1) # optional - kenzo + sage: S3 = simplicial_sets.Sphere(3) # optional - kenzo sage: KS1vS3 = KFiniteSimplicialSet(S1.wedge(S3)) # optional - kenzo sage: SS1vS3 = SFiniteSimplicialSet(KS1vS3, 3) # optional - kenzo sage: SS1vS3.homology() # optional - kenzo From 76beca07c8de9306b4a1174eac10b68240ad5724 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 12 Jul 2019 13:23:04 +0200 Subject: [PATCH 279/476] Implement serre-whitehead spectral sequence --- src/sage/interfaces/kenzo.py | 38 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index f1000099c12..0df350934d2 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -97,6 +97,7 @@ spectral_sequence_group = EclObject("spectral-sequence-group") spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") +serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") def Sphere(n): @@ -288,9 +289,9 @@ def matrix(self, p, i, j): - ``i`` -- the column of the differential domain. - ``j`` -- the row of the differential domain. - + EXAMPLES:: - + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo sage: S3 = Sphere(3) # optional -- kenzo sage: L = S3.loop_space() # optional -- kenzo @@ -303,7 +304,7 @@ def matrix(self, p, i, j): sage: EMS.matrix(1, -2 ,8) # optional -- kenzo [ 3 3 0] [-2 0 2] - [ 0 -3 -3] + [ 0 -3 -3] """ klist = spectral_sequence_differential_matrix(self._kenzo, p, i, j) plist = klist.python() @@ -312,7 +313,7 @@ def matrix(self, p, i, j): j = len(self.group(p, i-p, j+p-1).invariants()) return matrix(i,j) return matrix(plist) - + def differential(self, p, i, j): r""" Return the ``(p, i, j)`` differential morphism of the spectral sequence. @@ -324,9 +325,9 @@ def differential(self, p, i, j): - ``i`` -- the column of the differential domain. - ``j`` -- the row of the differential domain. - + EXAMPLES:: - + sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo sage: S3 = Sphere(3) # optional -- kenzo sage: L = S3.loop_space() # optional -- kenzo @@ -471,7 +472,7 @@ def basis(self, dim): sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo sage: kenzo_chcm # optional - kenzo - [K589 Chain-Complex] + [K... Chain-Complex] sage: for i in range(6): # optional - kenzo ....: print("Basis in dimension %i: %s" % (i, kenzo_chcm.basis(i))) # optional - kenzo Basis in dimension 0: ['G0G0', 'G0G1', 'G0G2'] @@ -639,11 +640,11 @@ def homotopy_group(self, n): return AbelianGroup(trgens) else: return AbelianGroup([]) - + def em_spectral_sequence(self): r""" Return the Eilenberg-Moore spectral sequence of self - + EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo @@ -660,6 +661,25 @@ def em_spectral_sequence(self): raise ValueError("Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets") return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) + def sw_spectral_sequence(self): + r""" + Return the Serre sequence of the first step of the Whitehead tower. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere + sage: S3 = Sphere(3) # optional -- kenzo + sage: E = S3.sw_spectral_sequence() # optional -- kenzo + sage: T = E.table(0,0,4,0,4) # optional -- kenzo + sage: T # optional -- kenzo + Z 0 0 Z 0 + 0 0 0 0 0 + Z 0 0 Z 0 + 0 0 0 0 0 + Z 0 0 Z 0 + """ + return KenzoSpectralSequence(serre_whitehead_spectral_sequence(self._kenzo)) + class KenzoSimplicialGroup(KenzoSimplicialSet): r""" From d0016d4ac7afed40fdaaff2ccfc21abd6707ee70 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 12 Jul 2019 13:33:50 +0200 Subject: [PATCH 280/476] implement serre spectral sequence of products --- src/sage/interfaces/kenzo.py | 38 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 0df350934d2..5f5882d8215 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -98,6 +98,7 @@ spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") +serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") def Sphere(n): @@ -668,18 +669,37 @@ def sw_spectral_sequence(self): EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere - sage: S3 = Sphere(3) # optional -- kenzo - sage: E = S3.sw_spectral_sequence() # optional -- kenzo - sage: T = E.table(0,0,4,0,4) # optional -- kenzo - sage: T # optional -- kenzo - Z 0 0 Z 0 - 0 0 0 0 0 - Z 0 0 Z 0 - 0 0 0 0 0 - Z 0 0 Z 0 + sage: S3 = Sphere(3) # optional -- kenzo + sage: E = S3.sw_spectral_sequence() # optional -- kenzo + sage: T = E.table(0, 0, 4, 0, 4) # optional -- kenzo + sage: T # optional -- kenzo + Z 0 0 Z 0 + 0 0 0 0 0 + Z 0 0 Z 0 + 0 0 0 0 0 + Z 0 0 Z 0 """ return KenzoSpectralSequence(serre_whitehead_spectral_sequence(self._kenzo)) + def serre_spectral_sequence(self): + r""" + Return the spectral sequence of self. + + The object self must be created as a cartesian product (twisted or not). + + sage: from sage.interfaces.kenzo import Sphere + sage: S2 = Sphere(2) # optional -- kenzo + sage: S3 = Sphere(3) # optional -- kenzo + sage: P = S2.cartesian_product(S3) # optional -- kenzo + sage: E = P.serre_spectral_sequence() # optional -- kenzo + sage: E.table(0, 0, 2, 0, 3) # optional -- kenzo + Z 0 Z + 0 0 0 + 0 0 0 + Z 0 Z + """ + return KenzoSpectralSequence(serre_spectral_sequence_product(self._kenzo)) + class KenzoSimplicialGroup(KenzoSimplicialSet): r""" From 4e9e11f06da5f853aa28caaf8d2a1571fb402a68 Mon Sep 17 00:00:00 2001 From: jodivaso Date: Tue, 17 Sep 2019 12:03:22 +0200 Subject: [PATCH 281/476] added wedge and join --- src/sage/interfaces/kenzo.py | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 5f5882d8215..bf887516105 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -99,6 +99,8 @@ eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") +wedge = EclObject("wedge") +join = EclObject("join") def Sphere(n): @@ -700,6 +702,58 @@ def serre_spectral_sequence(self): """ return KenzoSpectralSequence(serre_spectral_sequence_product(self._kenzo)) + def wedge(self, other): + r""" + Return the wedge of ``self`` and ``other``. + + INPUT: + + - ``other`` -- the Kenzo simplicial set with which the wedge is made + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: w = s2.wedge(s3) # optional - kenzo + sage: type(w) # optional - kenzo + + sage: [w.homology(i) for i in range(6)] # optional - kenzo + [Z, 0, Z, Z, 0, 0] + """ + wedge_kenzo = wedge(self._kenzo, other._kenzo) + return KenzoSimplicialSet(wedge_kenzo) + + def join(self, other): + r""" + Return the join of ``self`` and ``other``. + + INPUT: + + - ``other`` -- the Kenzo simplicial set with which the join is made + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: j = s2.join(s3) # optional - kenzo + sage: type(j) # optional - kenzo + + sage: [j.homology(i) for i in range(6)] # optional - kenzo + [Z, 0, 0, 0, 0, 0] + """ + join_kenzo = join(self._kenzo, other._kenzo) + return KenzoSimplicialSet(join_kenzo) + class KenzoSimplicialGroup(KenzoSimplicialSet): r""" From e5e318d7fe4c09362794c625fd918dd3bdeb1b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 25 Sep 2019 17:18:06 +0200 Subject: [PATCH 282/476] trac 27880 cleanup of kenzo file --- src/sage/interfaces/kenzo.py | 97 ++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index bf887516105..56f4057efed 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -40,8 +40,6 @@ from sage.libs.ecl import EclObject, ecl_eval, EclListIterator -from sage.env import SAGE_LOCAL -from sys import version # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we @@ -138,10 +136,9 @@ def MooreSpace(m, n): INPUT: - - ``m`` - A positive integer. The order of the nontrivial homology group. - - - ``n`` - The dimension in which the homology is not trivial + - ``m`` -- A positive integer. The order of the nontrivial homology group. + - ``n`` -- The dimension in which the homology is not trivial OUTPUT: @@ -174,7 +171,6 @@ def EilenbergMacLaneSpace(G, n): - ``n`` -- the dimension in which the homotopy is not trivial - OUTPUT: - A :class:`KenzoSimplicialGroup` @@ -248,6 +244,7 @@ def _repr_(self): kenzo_string = repr(self._kenzo) return kenzo_string[6:-1] + class KenzoSpectralSequence(KenzoObject): r""" Wrapper around Kenzo spectral sequences @@ -275,7 +272,7 @@ def group(self, p, i, j): sage: EMS.group(0, -1, 3) # optional -- kenzo Trivial group """ - invs = spectral_sequence_group(self._kenzo, p, i ,j).python() + invs = spectral_sequence_group(self._kenzo, p, i, j).python() if not invs: invs = [] return AdditiveAbelianGroup(invs) @@ -311,10 +308,10 @@ def matrix(self, p, i, j): """ klist = spectral_sequence_differential_matrix(self._kenzo, p, i, j) plist = klist.python() - if plist is None or plist==[None]: + if plist is None or plist == [None]: i = len(self.group(p, i, j).invariants()) - j = len(self.group(p, i-p, j+p-1).invariants()) - return matrix(i,j) + j = len(self.group(p, i - p, j + p - 1).invariants()) + return matrix(i, j) return matrix(plist) def differential(self, p, i, j): @@ -348,7 +345,7 @@ def differential(self, p, i, j): Morphism from module over Integer Ring with invariants (0, 0, 0) to module with invariants (0,) that sends the generators to [(2), (-2), (2)] """ domain = self.group(p, i, j) - codomain = self.group(p, i-p, j+p-1) + codomain = self.group(p, i - p, j + p - 1) M = self.matrix(p, i, j) images = [codomain(r) for r in M.rows()] return domain.hom(images, codomain=codomain) @@ -383,10 +380,10 @@ def table(self, p, i1, i2, j1, j2): """ from sage.misc.table import table groups = [] - for j in range(j2-j1+1): + for j in range(j2 - j1 + 1): row = [] - for i in range(i1, i2+1): - group = self.group(p,i,j2-j) + for i in range(i1, i2 + 1): + group = self.group(p, i, j2 - j) if group.invariants(): row.append(group.short_name()) else: @@ -413,16 +410,16 @@ def homology(self, n): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional - kenzo - sage: s2 = Sphere(2) # optional - kenzo - sage: s2 # optional - kenzo - [K1 Simplicial-Set] - sage: s2.homology(2) # optional - kenzo - Z + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s2 # optional - kenzo + [K1 Simplicial-Set] + sage: s2.homology(2) # optional - kenzo + Z """ echcm1 = echcm(self._kenzo) m1 = chcm_mat(echcm1, n) - m2 = chcm_mat(echcm1, n+1) + m2 = chcm_mat(echcm1, n + 1) homology = homologie(m1, m2) lhomomology = [i for i in EclListIterator(homology)] res = [] @@ -443,14 +440,16 @@ def tensor_product(self, other): - A :class:`KenzoChainComplex` - sage: from sage.interfaces.kenzo import Sphere # optional - kenzo - sage: s2 = Sphere(2) # optional - kenzo - sage: s3 = Sphere(3) # optional - kenzo - sage: p = s2.tensor_product(s3) # optional - kenzo - sage: type(p) # optional - kenzo - - sage: [p.homology(i) for i in range(8)] # optional - kenzo - [Z, 0, Z, Z, 0, Z, 0, 0] + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: p = s2.tensor_product(s3) # optional - kenzo + sage: type(p) # optional - kenzo + + sage: [p.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, Z, Z, 0, Z, 0, 0] """ return KenzoChainComplex(tnsr_prdc(self._kenzo, other._kenzo)) @@ -468,7 +467,7 @@ def basis(self, dim): EXAMPLES:: - sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) @@ -494,10 +493,12 @@ def differential(self, dim, comb): INPUT: - - ``dim``- An integer number + - ``dim``-- An integer number - - ``comb``- A list representing a formal sum of generators in the module - of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 + - ``comb``-- A list representing a formal sum of generators in + the module of dimension ``dim``. + + For example, to represent G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the generators must be in ascending order respect to the number after the second G in their representation; the parameter @@ -626,9 +627,13 @@ def suspension(self): def homotopy_group(self, n): """ Return the n'th homotopy group of ``self`` + INPUT: + - ``n`` - the dimension of the homotopy group to be computed + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: s2 = Sphere(2) # optional - kenzo sage: p = s2.cartesian_product(s2) # optional - kenzo @@ -646,7 +651,7 @@ def homotopy_group(self, n): def em_spectral_sequence(self): r""" - Return the Eilenberg-Moore spectral sequence of self + Return the Eilenberg-Moore spectral sequence of ``self``. EXAMPLES:: @@ -685,10 +690,12 @@ def sw_spectral_sequence(self): def serre_spectral_sequence(self): r""" - Return the spectral sequence of self. + Return the spectral sequence of ``self``. The object self must be created as a cartesian product (twisted or not). + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere sage: S2 = Sphere(2) # optional -- kenzo sage: S3 = Sphere(3) # optional -- kenzo @@ -893,11 +900,12 @@ def SChainComplex(kchaincomplex, start=0, end=15): def SAbstractSimplex(simplex, dim): r""" Convert an abstract simplex of Kenzo to an AbstractSimplex. + INPUT: - - ``simplex``- An abstract simplex of Kenzo. + - ``simplex`` -- An abstract simplex of Kenzo. - - ``dim``- The dimension of ``simplex``. + - ``dim``-- The dimension of ``simplex``. OUTPUT: @@ -929,9 +937,10 @@ def SAbstractSimplex(simplex, dim): def KAbstractSimplex(simplex): r""" Convert an AbstractSimplex in Sage to an abstract simplex of Kenzo. + INPUT: - - ``simplex``- An AbstractSimplex. + - ``simplex`` -- An AbstractSimplex. OUTPUT: @@ -949,7 +958,8 @@ def KAbstractSimplex(simplex): sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ - return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), 's'+str(hash(simplex)))) + return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), + 's' + str(hash(simplex)))) def KFiniteSimplicialSet(sset): @@ -958,7 +968,7 @@ def KFiniteSimplicialSet(sset): INPUT: - - ``sset``- A finite SimplicialSet. + - ``sset`` -- A finite SimplicialSet. OUTPUT: @@ -995,7 +1005,8 @@ def KFiniteSimplicialSet(sset): return f0 else: allcells = sset.cells() - namecells = {c:'cell_{}_{}'.format(d, allcells[d].index(c)) for d in allcells for c in allcells[d]} + namecells = {c: 'cell_{}_{}'.format(d, allcells[d].index(c)) + for d in allcells for c in allcells[d]} dim = sset.dimension() list_rslt = [namecells[i] for i in sset.n_cells(0)] if (dim > 0): @@ -1016,7 +1027,8 @@ def KFiniteSimplicialSet(sset): def SFiniteSimplicialSet(ksimpset, limit): - r"""Convert the ``limit``-skeleton of a finite simplicial set in Kenzo to a + r""" + Convert the ``limit``-skeleton of a finite simplicial set in Kenzo to a finite SimplicialSet in Sage. INPUT: @@ -1052,7 +1064,6 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: SS1vS3.homology() # optional - kenzo {0: 0, 1: Z, 2: 0, 3: Z} """ - list_orgn = orgn_aux1(ksimpset._kenzo).python() if nth(0, list_orgn).python()[0] == 'CRTS-PRDC': return SFiniteSimplicialSet(KenzoSimplicialSet(nth(1, list_orgn)), From b092e999c8cbeec19e2ed616f769c13f27d351c5 Mon Sep 17 00:00:00 2001 From: Ana Romero Date: Mon, 30 Sep 2019 11:09:04 +0200 Subject: [PATCH 283/476] Interface for morphisms of chain complexes added Spectral sequence of a bicomplex added --- src/sage/interfaces/kenzo.py | 492 ++++++++++++++++++++++++++++++++++- 1 file changed, 491 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 56f4057efed..38123a709af 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -99,7 +99,9 @@ serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") wedge = EclObject("wedge") join = EclObject("join") - +kmorphismchaincomplex_aux1 = EclObject("kmorphismchaincomplex_aux1") +bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") +nreverse = EclObject("nreverse") def Sphere(n): r""" @@ -1098,3 +1100,491 @@ def SFiniteSimplicialSet(ksimpset, limit): for i in range(len(simplices)): rslt[simplices[i]] = faces[i] return SimplicialSet(rslt) + + +class KenzoChainComplexMorphism(KenzoObject): + r""" + Wrapper to Kenzo morphisms between chain complexes. + """ + + def source_complex(self): + r""" + Return the source chain complex of the morphism. + OUTPUT: + - A :class:`KenzoChainComplex` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo + sage: differential_morphism # optional - kenzo + [K2 Morphism (degree -1): K1 -> K1] + sage: differential_morphism.source_complex() # optional - kenzo + [K1 Chain-Complex] + """ + return KenzoChainComplex(sorc_aux(self._kenzo)) + + def target_complex(self): + r""" + Return the target chain complex of the morphism. + OUTPUT: + - A :class:`KenzoChainComplex` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo + sage: differential_morphism # optional - kenzo + [K2 Morphism (degree -1): K1 -> K1] + sage: differential_morphism.target_complex() # optional - kenzo + [K1 Chain-Complex] + """ + return KenzoChainComplex(trgt_aux(self._kenzo)) + + def degree(self): + r""" + Return the degree of the morphism. + OUTPUT: + - An integer number, the degree of the morphism. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo + sage: differential_morphism # optional - kenzo + [K2 Morphism (degree -1): K1 -> K1] + sage: differential_morphism.degree() # optional - kenzo + -1 + sage: differential_morphism.composite(differential_morphism).degree() # optional - kenzo + -2 + sage: kenzo_chcm.null_morphism().degree() # optional - kenzo + 0 + """ + return degr_aux(self._kenzo).python() + + def orgn(self): + return str(orgn_aux1(self._kenzo)) + + def evaluation(self, dim, comb): + r""" + Apply the morphism on a combination ``comb`` of dimension ``dim``. + INPUT: + - ``dim``- An integer number + - ``comb``- A list representing a formal sum of generators in the module + of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 + we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the + generators must be in ascending order respect to the number after the + second G in their representation; the parameter + ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in + Kenzo. + OUTPUT: + - A Kenzo combination representing the result of applying the morphism on the formal + combination represented by ``comb`` in the chain complex ``self`` in + dimension ``dim``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo + sage: differential_morphism # optional - kenzo + [K2 Morphism (degree -1): K1 -> K1] + sage: dif_squared = differential_morphism.composite(differential_morphism) # optional - kenzo + sage: dif_squared # optional - kenzo + [K3 Morphism (degree -2): K1 -> K1] + sage: kenzo_chcm.basis(5) # optional - kenzo + ['G5G0', 'G5G1', 'G5G2'] + sage: kenzo_chcm.differential(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <6 * G4G0> + <-3 * G4G1> + ------------------------------------------------------------------------------ + + sage: differential_morphism.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <6 * G4G0> + <-3 * G4G1> + ------------------------------------------------------------------------------ + + sage: dif_squared.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 3} + ------------------------------------------------------------------------------ + + sage: id = kenzo_chcm.identity_morphism() # optional - kenzo + sage: idx2 = id.sum(id) # optional - kenzo + sage: id.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 5} + <1 * G5G0> + <2 * G5G2> + ------------------------------------------------------------------------------ + + sage: idx2.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 5} + <2 * G5G0> + <4 * G5G2> + ------------------------------------------------------------------------------ + + """ + if isinstance(dim, Integer): + if isinstance(comb, list): + cmbn_list = pairing(comb) + return KenzoObject(evaluation_aux1(self._kenzo, dim, cmbn_list)) + else: + raise ValueError("'comb' parameter must be a list") + else: + raise ValueError("'dim' parameter must be an integer number") + + def opposite(self): + r""" + Return the opposite morphism of ``self``, i.e., -1 x ``self``. + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: id = kenzo_chcm.identity_morphism() # optional - kenzo + sage: id # optional - kenzo + [K3 Morphism (degree 0): K1 -> K1] + sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id # optional - kenzo + [K4 Morphism (degree 0): K1 -> K1] + sage: kenzo_chcm.basis(4) # optional - kenzo + ['G4G0', 'G4G1'] + sage: id.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <2 * G4G0> + <-5 * G4G1> + ------------------------------------------------------------------------------ + + sage: opps_id.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <-2 * G4G0> + <5 * G4G1> + ------------------------------------------------------------------------------ + + """ + return KenzoChainComplexMorphism(opps(self._kenzo)) + + def composite(self, object=None): + r""" + Return the composite of ``self`` and the morphism(s) given by the parameter ``object``. + INPUT: + - ``object``- A KenzoChainComplexMorphism instance, a KenzoChainComplex instance, a tuple + of KenzoChainComplexMorphism and KenzoChainComplex instances, or None (default). + OUTPUT: + - A :class:`KenzoChainComplexMorphism`: if ``object`` is a KenzoChainComplexMorphism, the + composite of ``self`` and ``object`` is returned; if ``object`` is a KenzoChainComplex, + the composite of ``self`` and the differential morphism of ``object`` is returned; if + ``object`` is a tuple, the composite of ``self`` and the morphisms or the differential + morphisms of the given chain complexes in ``object`` is returned (if ``object``==None, + ``self`` morphism is returned). + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp22 = s2.tensor_product(s2) # optional - kenzo + sage: tp23 = s2.tensor_product(s3) # optional - kenzo + sage: id = tp22.identity_morphism() # optional - kenzo + sage: id # optional - kenzo + [K13 Morphism (degree 0): K3 -> K3] + sage: null = tp23.null_morphism(target = tp22, degree = 4) # optional - kenzo + sage: null # optional - kenzo + [K14 Morphism (degree 4): K11 -> K3] + sage: id.composite((tp22, null)) # optional - kenzo + [K15 Morphism (degree 3): K11 -> K3] + """ + if object==None: + return self + if isinstance(object, KenzoChainComplexMorphism): + return KenzoChainComplexMorphism(cmps(self._kenzo, object._kenzo)) + elif isinstance(object, KenzoChainComplex): + return KenzoChainComplexMorphism(cmps(self._kenzo, dffr_aux(object._kenzo))) + elif isinstance(object, tuple): + rslt = self._kenzo + for mrph in object: + rslt = cmps(rslt, mrph._kenzo) + return KenzoChainComplexMorphism(rslt) + + def sum(self, object=None): + r""" + Return a morphism, sum of the morphism ``self`` and the morphism(s) given by the parameter ``object``. + INPUT: + - ``object``- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism instances or None (default). + OUTPUT: + - A :class:`KenzoChainComplexMorphism`, sum of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object``==None, ``self`` morphism is returned). + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: id = kenzo_chcm.identity_morphism() # optional - kenzo + sage: id # optional - kenzo + [K3 Morphism (degree 0): K1 -> K1] + sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id # optional - kenzo + [K4 Morphism (degree 0): K1 -> K1] + sage: null = kenzo_chcm.null_morphism() # optional - kenzo + sage: null # optional - kenzo + [K5 Morphism (degree 0): K1 -> K1] + sage: idx2 = id.sum(id) # optional - kenzo + sage: idx5 = idx2.sum((opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo + sage: kenzo_chcm.basis(4) # optional - kenzo + ['G4G0', 'G4G1'] + sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <4 * G4G0> + <-10 * G4G1> + ------------------------------------------------------------------------------ + + sage: idx5.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <10 * G4G0> + <-25 * G4G1> + ------------------------------------------------------------------------------ + + """ + if object==None: + return self + if isinstance(object, KenzoChainComplexMorphism): + return KenzoChainComplexMorphism(add(self._kenzo, object._kenzo)) + elif isinstance(object, tuple): + rslt = self._kenzo + for mrph in object: + rslt = add(rslt, mrph._kenzo) + return KenzoChainComplexMorphism(rslt) + + def substract(self, object=None): + r""" + Return a morphism, difference of the morphism ``self`` and the morphism(s) given by the parameter ``object``. + INPUT: + - ``object``- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism instances or None (default). + OUTPUT: + - A :class:`KenzoChainComplexMorphism`, difference of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object``==None, ``self`` morphism is returned). For example, if ``object`` = (mrph1, mrph2, mrph3) the result is ``self`` - mrph1 - mrph2 - mrph3. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo + sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) + sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) + sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) + sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo + sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo + sage: kenzo_chcm # optional - kenzo + [K1 Chain-Complex] + sage: id = kenzo_chcm.identity_morphism() # optional - kenzo + sage: id # optional - kenzo + [K3 Morphism (degree 0): K1 -> K1] + sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id # optional - kenzo + [K4 Morphism (degree 0): K1 -> K1] + sage: null = kenzo_chcm.null_morphism() # optional - kenzo + sage: null # optional - kenzo + [K5 Morphism (degree 0): K1 -> K1] + sage: idx2 = id.substract(opps_id) # optional - kenzo + sage: opps_idx2 = idx2.substract((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo + sage: kenzo_chcm.basis(4) # optional - kenzo + ['G4G0', 'G4G1'] + sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <4 * G4G0> + <-10 * G4G1> + ------------------------------------------------------------------------------ + + sage: opps_idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + + ----------------------------------------------------------------------{CMBN 4} + <-4 * G4G0> + <10 * G4G1> + ------------------------------------------------------------------------------ + + """ + if object==None: + return self + if isinstance(object, KenzoChainComplexMorphism): + return KenzoChainComplexMorphism(sbtr(self._kenzo, object._kenzo)) + elif isinstance(object, tuple): + rslt = self._kenzo + for mrph in object: + rslt = sbtr(rslt, mrph._kenzo) + return KenzoChainComplexMorphism(rslt) + + def change_source_target_complex(self, source=None, target=None): + r""" + Build, from the morphism ``self``, a new morphism with ``source`` and ``target`` as source and target Kenzo chain complexes, respectively. + INPUT: + - ``source``- A KenzoChainComplex instance or None (default). + - ``target``- A KenzoChainComplex instance or None (default). + OUTPUT: + - A :class:`KenzoChainComplexMorphism` inheriting from ``self`` the degree (:degr slot in Kenzo), the algorithm (:intr slot in Kenzo) and the strategy (:strt slot in Kenzo). The source and target slots of this new morphism are given by the parameters ``source`` and ``target`` respectively; if any parameter is ommited, the corresponding slot is inherited from ``self``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo + sage: ZCC # optional - kenzo + [K1 Chain-Complex] + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp = s2.tensor_product(s3) # optional - kenzo + sage: tp # optional - kenzo + [K13 Chain-Complex] + sage: null = ZCC.null_morphism(tp) # optional - kenzo + sage: null # optional - kenzo + [K15 Morphism (degree 0): K1 -> K13] + sage: null.source_complex() # optional - kenzo + [K1 Chain-Complex] + sage: null2 = null.change_source_target_complex(source = tp) # optional - kenzo + sage: null2 # optional - kenzo + [K16 Morphism (degree 0): K13 -> K13] + sage: null2.source_complex() # optional - kenzo + [K13 Chain-Complex] + """ + source = source or self.source_complex() + target = target or self.target_complex() + return KenzoChainComplexMorphism(change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + + def destructive_change_source_target_complex(self, source=None, target=None): + r""" + Modify destructively the morphism ``self`` taking ``source`` and ``target`` as source and target Kenzo chain complexes of ``self``, respectively. + INPUT: + - ``source``- A KenzoChainComplex instance or None (default). + - ``target``- A KenzoChainComplex instance or None (default). + OUTPUT: + - A :class:`KenzoChainComplexMorphism`. The source and target slots of ``self`` are replaced respectively by the parameters ``source`` and ``target``; if any parameter is ommited, the corresponding slot is inherited from ``self``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo + sage: ZCC # optional - kenzo + [K1 Chain-Complex] + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp = s2.tensor_product(s3) # optional - kenzo + sage: tp # optional - kenzo + [K13 Chain-Complex] + sage: null = ZCC.null_morphism(tp) # optional - kenzo + sage: null # optional - kenzo + [K15 Morphism (degree 0): K1 -> K13] + sage: null.target_complex() # optional - kenzo + [K13 Chain-Complex] + sage: null.destructive_change_source_target_complex(target = ZCC) # optional - kenzo + [K15 Cohomology-Class on K1 of degree 0] + sage: null.target_complex() # optional - kenzo + [K1 Chain-Complex] + """ + source = source or self.source_complex() + target = target or self.target_complex() + return KenzoChainComplexMorphism(dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + + +def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): + return KenzoChainComplexMorphism(build_mrph_aux(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) + +def morphism_dictmat(morphism): + r""" + Computes a list of matrices in ECL associated to a morphism in Sage. + """ + rslt = EclObject([]) + source = morphism.domain() + d = source.differential() + for k in d.keys(): + rslt = EclObject(k).cons(s2k_matrix(morphism.in_degree(k))).cons(rslt) + return rslt + +def KChainComplexMorphism(morphism): + r""" + Construct a KenzoChainComplexMorphism from a ChainComplexMorphism in Sage. + INPUT: + - ``morphism`` - A morphism of chain complexes + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) + sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) + sage: g = KChainComplexMorphism(f) # optional - kenzo + sage: g + [K5 Morphism (degree 0): K1 -> K3] + sage: g.source_complex() # optional - kenzo + [K1 Chain-Complex] + sage: g.target_complex() # optional - kenzo + [K3 Chain-Complex] + """ + source = KChainComplex(morphism.domain()) + target = KChainComplex(morphism.codomain()) + matrix_list = morphism_dictmat(morphism) + return KenzoChainComplexMorphism(kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) + + +def s2k_listofmorphisms (l): + r""" + Computes a list of morphisms of chain complexes in Kenzo from a list of morphisms in Sage. + """ + rslt = EclObject([]) + for m in l: + rslt = EclObject(KChainComplexMorphism(m)._kenzo).cons(rslt) + return nreverse(rslt) + + +def BicomplexSpectralSequence(l): + r""" + Construct the spectral sequence associated to the bicomplex given by a list of morphisms. + INPUT: + - ``l`` - A list of morphisms of chain complexes + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: C1 = ChainComplex({1: matrix(ZZ, 0, 2, [])}, degree_of_differential=-1) + sage: C2 = ChainComplex({1: matrix(ZZ, 1, 2, [1, 0])},degree_of_differential=-1) + sage: C3 = ChainComplex({0: matrix(ZZ, 0,2 , [])},degree_of_differential=-1) + sage: M1 = Hom(C2,C1)({1: matrix(ZZ, 2, 2, [2, 0, 0, 2])}) + sage: M2 = Hom(C3,C2)({0: matrix(ZZ, 1, 2, [2, 0])}) + sage: l = [M1, M2] + sage: E = BicomplexSpectralSequence(l) + sage: E.group(2,0,1) + Additive abelian group isomorphic to Z/2 + Z + sage: E.table(3,0,2,0,2) + 0 0 0 + Z/2 + Z/4 0 0 + 0 0 Z + sage: E.matrix(2,2,0) + [ 0 -4] + [ 0 0] + """ + return KenzoSpectralSequence(bicomplex_spectral_sequence(s2k_listofmorphisms(l))) + + From 1bc57d3e5539e27cb1dc9ac0569b85e4a043a3fb Mon Sep 17 00:00:00 2001 From: jodivaso Date: Wed, 4 Dec 2019 10:25:04 +0100 Subject: [PATCH 284/476] added smash product --- src/sage/interfaces/kenzo.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 38123a709af..0ed69942e99 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -102,6 +102,7 @@ kmorphismchaincomplex_aux1 = EclObject("kmorphismchaincomplex_aux1") bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") nreverse = EclObject("nreverse") +smash_product = EclObject("smash-product") def Sphere(n): r""" @@ -763,6 +764,32 @@ def join(self, other): join_kenzo = join(self._kenzo, other._kenzo) return KenzoSimplicialSet(join_kenzo) + def smash_product(self, other): + r""" + Return the smash product of ``self`` and ``other``. + + INPUT: + + - ``other`` -- the Kenzo simplicial set with which the smash product is made + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: s = s2.smash_product(s3) # optional - kenzo + sage: type(s) # optional - kenzo + + sage: [s.homology(i) for i in range(6)] # optional - kenzo + [Z, 0, 0, 0, 0, Z] + """ + smash_kenzo = smash_product(self._kenzo, other._kenzo) + return KenzoSimplicialSet(smash_kenzo) + class KenzoSimplicialGroup(KenzoSimplicialSet): r""" From d62645d51da1d8d2ee2034b053982565d72c64ef Mon Sep 17 00:00:00 2001 From: jodivaso Date: Wed, 4 Dec 2019 12:37:55 +0100 Subject: [PATCH 285/476] some doc cleanup --- src/sage/interfaces/kenzo.py | 180 +++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 50 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 0ed69942e99..cb52e3b55ff 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -104,6 +104,7 @@ nreverse = EclObject("nreverse") smash_product = EclObject("smash-product") + def Sphere(n): r""" Return the ``n`` dimensional sphere as a Kenzo simplicial set. @@ -462,7 +463,7 @@ def basis(self, dim): INPUT: - - ``dim``- An integer number + - ``dim`` -- An integer number OUTPUT: @@ -526,7 +527,7 @@ def differential(self, dim, comb): [K... Chain-Complex] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] - sage: kenzo_chcm.differential(4, [1, 'G4G0']) # optional - kenzo + sage: kenzo_chcm.differential(4, [1, 'G4G0']) # optional - kenzo ----------------------------------------------------------------------{CMBN 3} <1 * G3G0> @@ -535,7 +536,7 @@ def differential(self, dim, comb): sage: kenzo_chcm.basis(5) # optional - kenzo ['G5G0', 'G5G1', 'G5G2'] - sage: kenzo_chcm.differential(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + sage: kenzo_chcm.differential(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo ----------------------------------------------------------------------{CMBN 4} <6 * G4G0> @@ -866,7 +867,7 @@ def KChainComplex(chain_complex): INPUT: - - ``chain_complex`` - A ChainComplex of degree = -1 + - ``chain_complex`` -- A ChainComplex of degree = -1 OUTPUT: @@ -898,11 +899,11 @@ def SChainComplex(kchaincomplex, start=0, end=15): INPUT: - - ``kchaincomplex``- A KenzoChainComplex + - ``kchaincomplex`` -- A KenzoChainComplex - - ``start``- An integer number (optional, default 0) + - ``start`` -- An integer number (optional, default 0) - - ``end``- An integer number greater than or equal to ``start`` (optional, default 15) + - ``end`` -- An integer number greater than or equal to ``start`` (optional, default 15) OUTPUT: @@ -1062,9 +1063,9 @@ def SFiniteSimplicialSet(ksimpset, limit): INPUT: - - ``ksimpset``- A finite simplicial set in Kenzo. + - ``ksimpset`` -- A finite simplicial set in Kenzo. - - ``limit``- A natural number. + - ``limit`` -- A natural number. OUTPUT: @@ -1137,9 +1138,13 @@ class KenzoChainComplexMorphism(KenzoObject): def source_complex(self): r""" Return the source chain complex of the morphism. + OUTPUT: + - A :class:`KenzoChainComplex` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1154,14 +1159,18 @@ def source_complex(self): sage: differential_morphism.source_complex() # optional - kenzo [K1 Chain-Complex] """ - return KenzoChainComplex(sorc_aux(self._kenzo)) - + return KenzoChainComplex(sorc_aux(self._kenzo)) + def target_complex(self): r""" Return the target chain complex of the morphism. + OUTPUT: + - A :class:`KenzoChainComplex` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1176,14 +1185,18 @@ def target_complex(self): sage: differential_morphism.target_complex() # optional - kenzo [K1 Chain-Complex] """ - return KenzoChainComplex(trgt_aux(self._kenzo)) + return KenzoChainComplex(trgt_aux(self._kenzo)) def degree(self): r""" Return the degree of the morphism. + OUTPUT: + - An integer number, the degree of the morphism. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1206,24 +1219,30 @@ def degree(self): def orgn(self): return str(orgn_aux1(self._kenzo)) - + def evaluation(self, dim, comb): r""" Apply the morphism on a combination ``comb`` of dimension ``dim``. + INPUT: - - ``dim``- An integer number - - ``comb``- A list representing a formal sum of generators in the module - of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 - we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the - generators must be in ascending order respect to the number after the - second G in their representation; the parameter - ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in - Kenzo. + + - ``dim`` -- An integer number + - ``comb`` -- A list representing a formal sum of generators in the module + of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 + we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the + generators must be in ascending order respect to the number after the + second G in their representation; the parameter + ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in + Kenzo. + OUTPUT: + - A Kenzo combination representing the result of applying the morphism on the formal - combination represented by ``comb`` in the chain complex ``self`` in - dimension ``dim``. + combination represented by ``comb`` in the chain complex ``self`` in + dimension ``dim``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1288,9 +1307,13 @@ def evaluation(self, dim, comb): def opposite(self): r""" Return the opposite morphism of ``self``, i.e., -1 x ``self``. + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1327,17 +1350,23 @@ def opposite(self): def composite(self, object=None): r""" Return the composite of ``self`` and the morphism(s) given by the parameter ``object``. + INPUT: - - ``object``- A KenzoChainComplexMorphism instance, a KenzoChainComplex instance, a tuple + + - ``object`` -- A KenzoChainComplexMorphism instance, a KenzoChainComplex instance, a tuple of KenzoChainComplexMorphism and KenzoChainComplex instances, or None (default). + OUTPUT: - - A :class:`KenzoChainComplexMorphism`: if ``object`` is a KenzoChainComplexMorphism, the - composite of ``self`` and ``object`` is returned; if ``object`` is a KenzoChainComplex, - the composite of ``self`` and the differential morphism of ``object`` is returned; if - ``object`` is a tuple, the composite of ``self`` and the morphisms or the differential - morphisms of the given chain complexes in ``object`` is returned (if ``object``==None, + + - A :class:`KenzoChainComplexMorphism`: if ``object`` is a KenzoChainComplexMorphism, the + composite of ``self`` and ``object`` is returned; if ``object`` is a KenzoChainComplex, + the composite of ``self`` and the differential morphism of ``object`` is returned; if + ``object`` is a tuple, the composite of ``self`` and the morphisms or the differential + morphisms of the given chain complexes in ``object`` is returned (if ``object``==None, ``self`` morphism is returned). + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: s2 = Sphere(2) # optional - kenzo sage: s3 = Sphere(3) # optional - kenzo @@ -1352,7 +1381,7 @@ def composite(self, object=None): sage: id.composite((tp22, null)) # optional - kenzo [K15 Morphism (degree 3): K11 -> K3] """ - if object==None: + if object is None: return self if isinstance(object, KenzoChainComplexMorphism): return KenzoChainComplexMorphism(cmps(self._kenzo, object._kenzo)) @@ -1367,11 +1396,19 @@ def composite(self, object=None): def sum(self, object=None): r""" Return a morphism, sum of the morphism ``self`` and the morphism(s) given by the parameter ``object``. + INPUT: - - ``object``- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism instances or None (default). + + - ``object`` -- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism + instances or None (default). + OUTPUT: - - A :class:`KenzoChainComplexMorphism`, sum of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object``==None, ``self`` morphism is returned). + + - A :class:`KenzoChainComplexMorphism`, sum of the morphism ``self`` and the morphism(s) + given by ``object`` (if ``object`` is None, ``self`` morphism is returned). + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1408,7 +1445,7 @@ def sum(self, object=None): ------------------------------------------------------------------------------ """ - if object==None: + if object is None: return self if isinstance(object, KenzoChainComplexMorphism): return KenzoChainComplexMorphism(add(self._kenzo, object._kenzo)) @@ -1420,12 +1457,22 @@ def sum(self, object=None): def substract(self, object=None): r""" - Return a morphism, difference of the morphism ``self`` and the morphism(s) given by the parameter ``object``. + Return a morphism, difference of the morphism ``self`` and the morphism(s) given by the + parameter ``object``. + INPUT: - - ``object``- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism instances or None (default). + + - ``object`` -- A KenzoChainComplexMorphism instance, a tuple of KenzoChainComplexMorphism + instances or None (default). + OUTPUT: - - A :class:`KenzoChainComplexMorphism`, difference of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object``==None, ``self`` morphism is returned). For example, if ``object`` = (mrph1, mrph2, mrph3) the result is ``self`` - mrph1 - mrph2 - mrph3. + + - A :class:`KenzoChainComplexMorphism`, difference of the morphism ``self`` and the + morphism(s) given by ``object`` (if ``object`` is None, ``self`` morphism is returned). + For example, if ``object`` = (mrph1, mrph2, mrph3) the result is ``self`` - mrph1 - mrph2 - mrph3. + EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) @@ -1462,7 +1509,7 @@ def substract(self, object=None): ------------------------------------------------------------------------------ """ - if object==None: + if object is None: return self if isinstance(object, KenzoChainComplexMorphism): return KenzoChainComplexMorphism(sbtr(self._kenzo, object._kenzo)) @@ -1474,13 +1521,24 @@ def substract(self, object=None): def change_source_target_complex(self, source=None, target=None): r""" - Build, from the morphism ``self``, a new morphism with ``source`` and ``target`` as source and target Kenzo chain complexes, respectively. + Build, from the morphism ``self``, a new morphism with ``source`` and ``target`` as source + and target Kenzo chain complexes, respectively. + INPUT: - - ``source``- A KenzoChainComplex instance or None (default). - - ``target``- A KenzoChainComplex instance or None (default). + + - ``source`` -- A KenzoChainComplex instance or None (default). + + - ``target`` -- A KenzoChainComplex instance or None (default). + OUTPUT: - - A :class:`KenzoChainComplexMorphism` inheriting from ``self`` the degree (:degr slot in Kenzo), the algorithm (:intr slot in Kenzo) and the strategy (:strt slot in Kenzo). The source and target slots of this new morphism are given by the parameters ``source`` and ``target`` respectively; if any parameter is ommited, the corresponding slot is inherited from ``self``. + + - A :class:`KenzoChainComplexMorphism` inheriting from ``self`` the degree (:degr slot in Kenzo), + the algorithm (:intr slot in Kenzo) and the strategy (:strt slot in Kenzo). The source and + target slots of this new morphism are given by the parameters ``source`` and ``target`` + respectively; if any parameter is ommited, the corresponding slot is inherited from ``self``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo sage: ZCC # optional - kenzo @@ -1507,13 +1565,23 @@ def change_source_target_complex(self, source=None, target=None): def destructive_change_source_target_complex(self, source=None, target=None): r""" - Modify destructively the morphism ``self`` taking ``source`` and ``target`` as source and target Kenzo chain complexes of ``self``, respectively. + Modify destructively the morphism ``self`` taking ``source`` and ``target`` as source and + target Kenzo chain complexes of ``self``, respectively. + INPUT: - - ``source``- A KenzoChainComplex instance or None (default). - - ``target``- A KenzoChainComplex instance or None (default). + + - ``source`` -- A KenzoChainComplex instance or None (default). + + - ``target`` -- A KenzoChainComplex instance or None (default). + OUTPUT: - - A :class:`KenzoChainComplexMorphism`. The source and target slots of ``self`` are replaced respectively by the parameters ``source`` and ``target``; if any parameter is ommited, the corresponding slot is inherited from ``self``. + + - A :class:`KenzoChainComplexMorphism`. The source and target slots of ``self`` are replaced + respectively by the parameters ``source`` and ``target``; if any parameter is ommited, the + corresponding slot is inherited from ``self``. + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo sage: ZCC # optional - kenzo @@ -1541,6 +1609,7 @@ def destructive_change_source_target_complex(self, source=None, target=None): def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): return KenzoChainComplexMorphism(build_mrph_aux(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) + def morphism_dictmat(morphism): r""" Computes a list of matrices in ECL associated to a morphism in Sage. @@ -1552,14 +1621,21 @@ def morphism_dictmat(morphism): rslt = EclObject(k).cons(s2k_matrix(morphism.in_degree(k))).cons(rslt) return rslt + def KChainComplexMorphism(morphism): r""" Construct a KenzoChainComplexMorphism from a ChainComplexMorphism in Sage. + INPUT: - - ``morphism`` - A morphism of chain complexes + + - ``morphism`` -- A morphism of chain complexes + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) @@ -1577,7 +1653,7 @@ def KChainComplexMorphism(morphism): return KenzoChainComplexMorphism(kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) -def s2k_listofmorphisms (l): +def s2k_listofmorphisms(l): r""" Computes a list of morphisms of chain complexes in Kenzo from a list of morphisms in Sage. """ @@ -1590,11 +1666,17 @@ def s2k_listofmorphisms (l): def BicomplexSpectralSequence(l): r""" Construct the spectral sequence associated to the bicomplex given by a list of morphisms. + INPUT: - - ``l`` - A list of morphisms of chain complexes + + - ``l`` -- A list of morphisms of chain complexes + OUTPUT: + - A :class:`KenzoChainComplexMorphism` + EXAMPLES:: + sage: C1 = ChainComplex({1: matrix(ZZ, 0, 2, [])}, degree_of_differential=-1) sage: C2 = ChainComplex({1: matrix(ZZ, 1, 2, [1, 0])},degree_of_differential=-1) sage: C3 = ChainComplex({0: matrix(ZZ, 0,2 , [])},degree_of_differential=-1) @@ -1613,5 +1695,3 @@ def BicomplexSpectralSequence(l): [ 0 0] """ return KenzoSpectralSequence(bicomplex_spectral_sequence(s2k_listofmorphisms(l))) - - From c0fa81ac8df03cb690f4bd7fe9d5d8975017e14a Mon Sep 17 00:00:00 2001 From: jodivaso Date: Fri, 6 Dec 2019 15:47:06 +0100 Subject: [PATCH 286/476] more doc cleanup --- src/sage/interfaces/kenzo.py | 65 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index cb52e3b55ff..1d16c8b02a7 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -670,7 +670,8 @@ def em_spectral_sequence(self): 0 0 0 0 0 """ if self.homology(1).invariants(): - raise ValueError("Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets") + raise ValueError("""Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""") return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) def sw_spectral_sequence(self): @@ -1395,7 +1396,8 @@ def composite(self, object=None): def sum(self, object=None): r""" - Return a morphism, sum of the morphism ``self`` and the morphism(s) given by the parameter ``object``. + Return a morphism, sum of the morphism ``self`` and the morphism(s) given + by the parameter ``object``. INPUT: @@ -1469,7 +1471,8 @@ def substract(self, object=None): - A :class:`KenzoChainComplexMorphism`, difference of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object`` is None, ``self`` morphism is returned). - For example, if ``object`` = (mrph1, mrph2, mrph3) the result is ``self`` - mrph1 - mrph2 - mrph3. + For example, if ``object`` = (mrph1, mrph2, mrph3) the result is + ``self`` - mrph1 - mrph2 - mrph3. EXAMPLES:: @@ -1603,16 +1606,36 @@ def destructive_change_source_target_complex(self, source=None, target=None): """ source = source or self.source_complex() target = target or self.target_complex() - return KenzoChainComplexMorphism(dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism( + dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): - return KenzoChainComplexMorphism(build_mrph_aux(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) + return KenzoChainComplexMorphism( + build_mrph_aux(source_complex._kenzo, target_complex._kenzo, + degree, algorithm, ":"+strategy, orgn)) def morphism_dictmat(morphism): r""" Computes a list of matrices in ECL associated to a morphism in Sage. + + INPUT: + + - ``morphism`` -- A morphism of chain complexes + + OUTPUT: + + - A :class:`EclObject` + + EXAMPLES:: + + sage: X = simplicial_complexes.Simplex(1) + sage: Y = simplicial_complexes.Simplex(0) + sage: g = Hom(X,Y)({0:0, 1:0}) + sage: f = g.associated_chain_complex_morphism() + sage: morphism_dictmat(f) # optional - kenzo + """ rslt = EclObject([]) source = morphism.domain() @@ -1650,12 +1673,32 @@ def KChainComplexMorphism(morphism): source = KChainComplex(morphism.domain()) target = KChainComplex(morphism.codomain()) matrix_list = morphism_dictmat(morphism) - return KenzoChainComplexMorphism(kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism( + kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) def s2k_listofmorphisms(l): r""" Computes a list of morphisms of chain complexes in Kenzo from a list of morphisms in Sage. + + INPUT: + + - ``l`` -- A list of morphisms of chain complexes + + OUTPUT: + + - A :class:`EclObject` + + EXAMPLES:: + + sage: C1 = ChainComplex({1: matrix(ZZ, 0, 2, [])}, degree_of_differential=-1) + sage: C2 = ChainComplex({1: matrix(ZZ, 1, 2, [1, 0])},degree_of_differential=-1) + sage: C3 = ChainComplex({0: matrix(ZZ, 0,2 , [])},degree_of_differential=-1) + sage: M1 = Hom(C2,C1)({1: matrix(ZZ, 2, 2, [2, 0, 0, 2])}) + sage: M2 = Hom(C3,C2)({0: matrix(ZZ, 1, 2, [2, 0])}) + sage: l = [M1, M2] + sage: s2k_listofmorphisms(l) # optional - kenzo + K3] [K17 Morphism (degree 0): K6 -> K1])> """ rslt = EclObject([]) for m in l: @@ -1673,7 +1716,7 @@ def BicomplexSpectralSequence(l): OUTPUT: - - A :class:`KenzoChainComplexMorphism` + - A :class:`KenzoSpectralSequence` EXAMPLES:: @@ -1683,14 +1726,14 @@ def BicomplexSpectralSequence(l): sage: M1 = Hom(C2,C1)({1: matrix(ZZ, 2, 2, [2, 0, 0, 2])}) sage: M2 = Hom(C3,C2)({0: matrix(ZZ, 1, 2, [2, 0])}) sage: l = [M1, M2] - sage: E = BicomplexSpectralSequence(l) - sage: E.group(2,0,1) + sage: E = BicomplexSpectralSequence(l) # optional - kenzo + sage: E.group(2,0,1) # optional - kenzo Additive abelian group isomorphic to Z/2 + Z - sage: E.table(3,0,2,0,2) + sage: E.table(3,0,2,0,2) # optional - kenzo 0 0 0 Z/2 + Z/4 0 0 0 0 Z - sage: E.matrix(2,2,0) + sage: E.matrix(2,2,0) # optional - kenzo [ 0 -4] [ 0 0] """ From b3a0ba01b1d49d8912ee7d2201b78d077647d70a Mon Sep 17 00:00:00 2001 From: jodivaso Date: Fri, 6 Dec 2019 16:31:47 +0100 Subject: [PATCH 287/476] added missing documentation and fixed syntax for optional package in the examples --- src/sage/interfaces/kenzo.py | 120 ++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 1d16c8b02a7..5050638d450 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -268,12 +268,12 @@ def group(self, p, i, j): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo - sage: S2 = Sphere(2) # optional -- kenzo - sage: EMS = S2.em_spectral_sequence() # optional -- kenzo - sage: EMS.group(0, -1, 2) # optional -- kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: S2 = Sphere(2) # optional - kenzo + sage: EMS = S2.em_spectral_sequence() # optional - kenzo + sage: EMS.group(0, -1, 2) # optional - kenzo Additive abelian group isomorphic to Z - sage: EMS.group(0, -1, 3) # optional -- kenzo + sage: EMS.group(0, -1, 3) # optional - kenzo Trivial group """ invs = spectral_sequence_group(self._kenzo, p, i, j).python() @@ -296,16 +296,16 @@ def matrix(self, p, i, j): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo - sage: S3 = Sphere(3) # optional -- kenzo - sage: L = S3.loop_space() # optional -- kenzo - sage: EMS = L.em_spectral_sequence() # optional -- kenzo - sage: EMS.table(1, -5, -2, 5, 8) # optional -- kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: S3 = Sphere(3) # optional - kenzo + sage: L = S3.loop_space() # optional - kenzo + sage: EMS = L.em_spectral_sequence() # optional - kenzo + sage: EMS.table(1, -5, -2, 5, 8) # optional - kenzo 0 Z Z + Z + Z Z + Z + Z 0 0 0 0 0 0 Z Z + Z 0 0 0 0 - sage: EMS.matrix(1, -2 ,8) # optional -- kenzo + sage: EMS.matrix(1, -2 ,8) # optional - kenzo [ 3 3 0] [-2 0 2] [ 0 -3 -3] @@ -332,20 +332,20 @@ def differential(self, p, i, j): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo - sage: S3 = Sphere(3) # optional -- kenzo - sage: L = S3.loop_space() # optional -- kenzo - sage: EMS = L.em_spectral_sequence() # optional -- kenzo - sage: EMS.table(1,-5,-2,5,8) # optional -- kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: S3 = Sphere(3) # optional - kenzo + sage: L = S3.loop_space() # optional - kenzo + sage: EMS = L.em_spectral_sequence() # optional - kenzo + sage: EMS.table(1,-5,-2,5,8) # optional - kenzo 0 Z Z + Z + Z Z + Z + Z 0 0 0 0 0 0 Z Z + Z 0 0 0 0 - sage: EMS.matrix(1, -3, 8) # optional -- kenzo + sage: EMS.matrix(1, -3, 8) # optional - kenzo [ 2] [-2] [ 2] - sage: EMS.differential(1, -3, 8) # optional -- kenzo + sage: EMS.differential(1, -3, 8) # optional - kenzo Morphism from module over Integer Ring with invariants (0, 0, 0) to module with invariants (0,) that sends the generators to [(2), (-2), (2)] """ domain = self.group(p, i, j) @@ -372,10 +372,10 @@ def table(self, p, i1, i2, j1, j2): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo - sage: S2 = Sphere(2) # optional -- kenzo - sage: EMS = S2.em_spectral_sequence() # optional -- kenzo - sage: EMS.table(0, -2, 2, -2, 2) # optional -- kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: S2 = Sphere(2) # optional - kenzo + sage: EMS = S2.em_spectral_sequence() # optional - kenzo + sage: EMS.table(0, -2, 2, -2, 2) # optional - kenzo 0 Z 0 0 0 0 0 0 0 0 0 0 Z 0 0 @@ -659,10 +659,10 @@ def em_spectral_sequence(self): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional -- kenzo - sage: S2 = Sphere(2) # optional -- kenzo - sage: EMS = S2.em_spectral_sequence() # optional -- kenzo - sage: EMS.table(0, -2, 2, -2, 2) # optional -- kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: S2 = Sphere(2) # optional - kenzo + sage: EMS = S2.em_spectral_sequence() # optional - kenzo + sage: EMS.table(0, -2, 2, -2, 2) # optional - kenzo 0 Z 0 0 0 0 0 0 0 0 0 0 Z 0 0 @@ -681,10 +681,10 @@ def sw_spectral_sequence(self): EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere - sage: S3 = Sphere(3) # optional -- kenzo - sage: E = S3.sw_spectral_sequence() # optional -- kenzo - sage: T = E.table(0, 0, 4, 0, 4) # optional -- kenzo - sage: T # optional -- kenzo + sage: S3 = Sphere(3) # optional - kenzo + sage: E = S3.sw_spectral_sequence() # optional - kenzo + sage: T = E.table(0, 0, 4, 0, 4) # optional - kenzo + sage: T # optional - kenzo Z 0 0 Z 0 0 0 0 0 0 Z 0 0 Z 0 @@ -702,11 +702,11 @@ def serre_spectral_sequence(self): EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere - sage: S2 = Sphere(2) # optional -- kenzo - sage: S3 = Sphere(3) # optional -- kenzo - sage: P = S2.cartesian_product(S3) # optional -- kenzo - sage: E = P.serre_spectral_sequence() # optional -- kenzo - sage: E.table(0, 0, 2, 0, 3) # optional -- kenzo + sage: S2 = Sphere(2) # optional - kenzo + sage: S3 = Sphere(3) # optional - kenzo + sage: P = S2.cartesian_product(S3) # optional - kenzo + sage: E = P.serre_spectral_sequence() # optional - kenzo + sage: E.table(0, 0, 2, 0, 3) # optional - kenzo Z 0 Z 0 0 0 0 0 0 @@ -832,6 +832,21 @@ def k2s_matrix(kmatrix): def s2k_matrix(smatrix): r""" Convert a matrix of Sage to an array of ECL. + + INPUT: + + - ``smatrix`` -- A matrix in Sage + + OUTPUT: + + - A :class:`EclObject` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import s2k_matrix # optional - kenzo + sage: A = Matrix([[1,2,3],[3,2,1],[1,1,1]]) + sage: s2k_matrix(A) # optional - kenzo + """ initcontents = [] dimensions = smatrix.dimensions() @@ -844,6 +859,23 @@ def s2k_dictmat(sdictmat): r""" Convert a dictionary in Sage, whose values are matrices, to an assoc list in ECL. + + INPUT: + + - ``sdictmat`` -- A dictionary in Sage + + OUTPUT: + + - A :class:`EclObject` + + EXAMPLES:: + sage: from sage.interfaces.kenzo import s2k_dictmat # optional - kenzo + sage: A = Matrix([[1,2,3],[3,2,1],[1,1,1]]) + sage: B = Matrix([[1,2],[2,1],[1,1]]) + sage: d = {1 : A, 2 : B} + sage: s2k_dictmat(d) # optional - kenzo + + """ rslt = EclObject([]) for k in sdictmat.keys(): @@ -854,6 +886,20 @@ def s2k_dictmat(sdictmat): def pairing(slist): r""" Convert a list of Sage (which has an even length) to an assoc list in ECL. + + INPUT: + + - ``slist`` -- A list in Sage + + OUTPUT: + + - A :class:`EclObject` + + EXAMPLES:: + sage: from sage.interfaces.kenzo import pairing # optional - kenzo + sage: l = [1,2,3] + sage: pairing(l) # optional - kenzo + """ rslt = EclObject([]) for k in range(len(slist) - 1, 0, -2): @@ -1363,8 +1409,8 @@ def composite(self, object=None): composite of ``self`` and ``object`` is returned; if ``object`` is a KenzoChainComplex, the composite of ``self`` and the differential morphism of ``object`` is returned; if ``object`` is a tuple, the composite of ``self`` and the morphisms or the differential - morphisms of the given chain complexes in ``object`` is returned (if ``object``==None, - ``self`` morphism is returned). + morphisms of the given chain complexes in ``object`` is returned (if ``object`` is + None, ``self`` morphism is returned). EXAMPLES:: From 65b47958718f30b62b4b1201b47d7bb5ebbe5e3f Mon Sep 17 00:00:00 2001 From: jodivaso Date: Mon, 9 Dec 2019 11:24:27 +0100 Subject: [PATCH 288/476] added missing functions, fixed tests and more work on doc --- src/sage/interfaces/kenzo.py | 244 +++++++++++++++++++++++------------ 1 file changed, 165 insertions(+), 79 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 5050638d450..b48a853aabe 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -103,6 +103,20 @@ bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") nreverse = EclObject("nreverse") smash_product = EclObject("smash-product") +build_mrph_aux = EclObject("build-mrph-aux") +zero_mrph = EclObject("zero-mrph") +idnt_mrph = EclObject("idnt-mrph") +dffr_aux = EclObject("dffr-aux") +sorc_aux = EclObject("sorc-aux") +trgt_aux = EclObject("trgt-aux") +degr_aux = EclObject("degr-aux") +evaluation_aux1 = EclObject("evaluation-aux1") +opps = EclObject("opps") +cmps = EclObject("cmps") +add = EclObject("add") +sbtr = EclObject("sbtr") +change_sorc_trgt_aux = EclObject("change-sorc-trgt-aux") +dstr_change_sorc_trgt_aux = EclObject("dstr-change-sorc-trgt-aux") def Sphere(n): @@ -306,9 +320,9 @@ def matrix(self, p, i, j): 0 0 Z Z + Z 0 0 0 0 sage: EMS.matrix(1, -2 ,8) # optional - kenzo - [ 3 3 0] - [-2 0 2] - [ 0 -3 -3] + [ 3 -2 0] + [ 3 0 -3] + [ 0 2 -3] """ klist = spectral_sequence_differential_matrix(self._kenzo, p, i, j) plist = klist.python() @@ -342,16 +356,14 @@ def differential(self, p, i, j): 0 0 Z Z + Z 0 0 0 0 sage: EMS.matrix(1, -3, 8) # optional - kenzo - [ 2] - [-2] - [ 2] + [ 2 -2 2] sage: EMS.differential(1, -3, 8) # optional - kenzo Morphism from module over Integer Ring with invariants (0, 0, 0) to module with invariants (0,) that sends the generators to [(2), (-2), (2)] """ domain = self.group(p, i, j) codomain = self.group(p, i - p, j + p - 1) M = self.matrix(p, i, j) - images = [codomain(r) for r in M.rows()] + images = [codomain(r) for r in M.columns()] return domain.hom(images, codomain=codomain) def table(self, p, i1, i2, j1, j2): @@ -491,29 +503,94 @@ def basis(self, dim): """ return basis_aux1(self._kenzo, dim).python() - def differential(self, dim, comb): + def identity_morphism(self): r""" - Return the differential of a combination. + Return the identity morphism (degree 0) between ``self`` and itself. + + OUTPUT: + + - A :class:`KenzoChainComplexMorphism` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: tp = s2.tensor_product(s2) # optional - kenzo + sage: id = tp.identity_morphism() # optional - kenzo + sage: type(id) # optional - kenzo + + """ + return KenzoChainComplexMorphism(idnt_mrph(self._kenzo)) + + def null_morphism(self, target=None, degree=None): + r""" + Return the null morphism between the chain complexes ``self`` and ``target`` + of degree ``degree``. INPUT: + + - ``target`` -- A KenzoChainComplex or None (default). + - ``degree`` -- An integer number or None (default). - - ``dim``-- An integer number + OUTPUT: + + - A :class:`KenzoChainComplexMorphism` representing the null morphism between + ``self`` and ``target`` of degree ``degree``. If ``target`` takes None value, + ``self`` is assumed as the target chain complex; if ``degree`` takes None value, + 0 is assumed as the degree of the null morphism. - - ``comb``-- A list representing a formal sum of generators in - the module of dimension ``dim``. + EXAMPLES:: - For example, to represent G7G12 + 3*G7G0 - 5*G7G3 - we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the - generators must be in ascending order respect to the number after the - second G in their representation; the parameter + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp22 = s2.tensor_product(s2) # optional - kenzo + sage: tp22 # optional - kenzo # random + [K8 Chain-Complex] + sage: tp23 = s2.tensor_product(s3) # optional - kenzo + sage: tp23 # optional - kenzo # random + [K11 Chain-Complex] + sage: null1 = tp22.null_morphism() # optional - kenzo + sage: null1 # optional - kenzo # random + [K13 Morphism (degree 0): K8 -> K8] + sage: null2 = tp22.null_morphism(target = tp23, degree = -3) # optional - kenzo + sage: null2 # optional - kenzo # random + [K14 Morphism (degree -3): K8 -> K11] + """ + if target is None: + target = self + if degree is None: + degree = 0 + if not isinstance(target, KenzoChainComplex): + raise ValueError("'target' parameter must be a KenzoChainComplex instance") + elif (not degree == 0) and (not degree.is_integer()): + raise ValueError("'degree' parameter must be an Integer number") + else: + return KenzoChainComplexMorphism(zero_mrph(self._kenzo, target._kenzo, degree)) + + def differential(self, dim=None, comb=None): + r""" + Return the differential of a combination. + + INPUT: + + - ``dim`` -- An integer number or None (default) + + - ``comb`` -- A list representing a formal sum of generators in the module + of dimension ``dim`` or None (default). For example, to represent + G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. + Note that the generators must be in ascending order respect to the number + after the second G in their representation; the parameter ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in Kenzo. OUTPUT: - - A Kenzo combination representing the differential of the formal - combination represented by ``comb`` in the chain complex ``self`` in - dimension ``dim``. + - If ``dim`` and ``comb`` are not None, it returns a Kenzo combination + representing the differential of the formal combination represented by + ``comb`` in the chain complex ``self`` in dimension ``dim``. On the other + hand, if `dim`` or ``comb`` (or both) take None value, the differential + :class:`KenzoMorphismChainComplex` of ``self`` is returned. EXAMPLES:: @@ -544,8 +621,11 @@ def differential(self, dim, comb): ------------------------------------------------------------------------------ """ - cmbn_list = pairing(comb) - return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) + if dim!=None and comb!=None: + cmbn_list = pairing(comb) + return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) + else: + return KenzoChainComplexMorphism(dffr_aux(self._kenzo)) def orgn(self): return str(orgn_aux1(self._kenzo)) @@ -1198,12 +1278,12 @@ def source_complex(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo + sage: differential_morphism # optional - kenzo # random [K2 Morphism (degree -1): K1 -> K1] - sage: differential_morphism.source_complex() # optional - kenzo + sage: differential_morphism.source_complex() # optional - kenzo # random [K1 Chain-Complex] """ return KenzoChainComplex(sorc_aux(self._kenzo)) @@ -1224,12 +1304,12 @@ def target_complex(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo + sage: differential_morphism # optional - kenzo # random [K2 Morphism (degree -1): K1 -> K1] - sage: differential_morphism.target_complex() # optional - kenzo + sage: differential_morphism.target_complex() # optional - kenzo # random [K1 Chain-Complex] """ return KenzoChainComplex(trgt_aux(self._kenzo)) @@ -1250,10 +1330,10 @@ def degree(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo + sage: differential_morphism # optional - kenzo # random [K2 Morphism (degree -1): K1 -> K1] sage: differential_morphism.degree() # optional - kenzo -1 @@ -1296,13 +1376,13 @@ def evaluation(self, dim, comb): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo + sage: differential_morphism # optional - kenzo # random [K2 Morphism (degree -1): K1 -> K1] sage: dif_squared = differential_morphism.composite(differential_morphism) # optional - kenzo - sage: dif_squared # optional - kenzo + sage: dif_squared # optional - kenzo # random [K3 Morphism (degree -2): K1 -> K1] sage: kenzo_chcm.basis(5) # optional - kenzo ['G5G0', 'G5G1', 'G5G2'] @@ -1342,7 +1422,7 @@ def evaluation(self, dim, comb): ------------------------------------------------------------------------------ """ - if isinstance(dim, Integer): + if dim.is_integer(): if isinstance(comb, list): cmbn_list = pairing(comb) return KenzoObject(evaluation_aux1(self._kenzo, dim, cmbn_list)) @@ -1367,13 +1447,13 @@ def opposite(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: id # optional - kenzo # random [K3 Morphism (degree 0): K1 -> K1] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo + sage: opps_id # optional - kenzo # random [K4 Morphism (degree 0): K1 -> K1] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] @@ -1420,12 +1500,12 @@ def composite(self, object=None): sage: tp22 = s2.tensor_product(s2) # optional - kenzo sage: tp23 = s2.tensor_product(s3) # optional - kenzo sage: id = tp22.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: id # optional - kenzo # random [K13 Morphism (degree 0): K3 -> K3] sage: null = tp23.null_morphism(target = tp22, degree = 4) # optional - kenzo - sage: null # optional - kenzo + sage: null # optional - kenzo # random [K14 Morphism (degree 4): K11 -> K3] - sage: id.composite((tp22, null)) # optional - kenzo + sage: id.composite((tp22, null)) # optional - kenzo # random [K15 Morphism (degree 3): K11 -> K3] """ if object is None: @@ -1463,16 +1543,16 @@ def sum(self, object=None): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: id # optional - kenzo # random [K3 Morphism (degree 0): K1 -> K1] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo + sage: opps_id # optional - kenzo # random [K4 Morphism (degree 0): K1 -> K1] sage: null = kenzo_chcm.null_morphism() # optional - kenzo - sage: null # optional - kenzo + sage: null # optional - kenzo # random [K5 Morphism (degree 0): K1 -> K1] sage: idx2 = id.sum(id) # optional - kenzo sage: idx5 = idx2.sum((opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo @@ -1528,16 +1608,16 @@ def substract(self, object=None): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo + sage: kenzo_chcm # optional - kenzo # random [K1 Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: id # optional - kenzo # random [K3 Morphism (degree 0): K1 -> K1] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo + sage: opps_id # optional - kenzo # random [K4 Morphism (degree 0): K1 -> K1] sage: null = kenzo_chcm.null_morphism() # optional - kenzo - sage: null # optional - kenzo + sage: null # optional - kenzo # random [K5 Morphism (degree 0): K1 -> K1] sage: idx2 = id.substract(opps_id) # optional - kenzo sage: opps_idx2 = idx2.substract((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo @@ -1588,24 +1668,25 @@ def change_source_target_complex(self, source=None, target=None): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional - kenzo - sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo - sage: ZCC # optional - kenzo + sage: from sage.interfaces.kenzo import Sphere, KenzoChainComplex # optional - kenzo + sage: from sage.libs.ecl import ecl_eval + sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo + sage: ZCC # optional - kenzo # random [K1 Chain-Complex] - sage: s2 = Sphere(2) # optional - kenzo - sage: s3 = Sphere(3) # optional - kenzo - sage: tp = s2.tensor_product(s3) # optional - kenzo - sage: tp # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp = s2.tensor_product(s3) # optional - kenzo + sage: tp # optional - kenzo # random [K13 Chain-Complex] - sage: null = ZCC.null_morphism(tp) # optional - kenzo - sage: null # optional - kenzo + sage: null = ZCC.null_morphism(tp) # optional - kenzo + sage: null # optional - kenzo # random [K15 Morphism (degree 0): K1 -> K13] - sage: null.source_complex() # optional - kenzo + sage: null.source_complex() # optional - kenzo # random [K1 Chain-Complex] - sage: null2 = null.change_source_target_complex(source = tp) # optional - kenzo - sage: null2 # optional - kenzo + sage: null2 = null.change_source_target_complex(source = tp) # optional - kenzo + sage: null2 # optional - kenzo # random [K16 Morphism (degree 0): K13 -> K13] - sage: null2.source_complex() # optional - kenzo + sage: null2.source_complex() # optional - kenzo # random [K13 Chain-Complex] """ source = source or self.source_complex() @@ -1631,23 +1712,24 @@ def destructive_change_source_target_complex(self, source=None, target=None): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere # optional - kenzo - sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo - sage: ZCC # optional - kenzo + sage: from sage.interfaces.kenzo import Sphere, KenzoChainComplex # optional - kenzo + sage: from sage.libs.ecl import ecl_eval + sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo + sage: ZCC # optional - kenzo # random [K1 Chain-Complex] - sage: s2 = Sphere(2) # optional - kenzo - sage: s3 = Sphere(3) # optional - kenzo - sage: tp = s2.tensor_product(s3) # optional - kenzo - sage: tp # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: tp = s2.tensor_product(s3) # optional - kenzo + sage: tp # optional - kenzo # random [K13 Chain-Complex] - sage: null = ZCC.null_morphism(tp) # optional - kenzo - sage: null # optional - kenzo + sage: null = ZCC.null_morphism(tp) # optional - kenzo + sage: null # optional - kenzo # random [K15 Morphism (degree 0): K1 -> K13] - sage: null.target_complex() # optional - kenzo + sage: null.target_complex() # optional - kenzo # random [K13 Chain-Complex] - sage: null.destructive_change_source_target_complex(target = ZCC) # optional - kenzo + sage: null.destructive_change_source_target_complex(target = ZCC) # optional - kenzo # random [K15 Cohomology-Class on K1 of degree 0] - sage: null.target_complex() # optional - kenzo + sage: null.target_complex() # optional - kenzo # random [K1 Chain-Complex] """ source = source or self.source_complex() @@ -1676,11 +1758,12 @@ def morphism_dictmat(morphism): EXAMPLES:: + sage: from sage.interfaces.kenzo import morphism_dictmat # optional - kenzo sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: f = g.associated_chain_complex_morphism() - sage: morphism_dictmat(f) # optional - kenzo + sage: morphism_dictmat(f) # optional - kenzo """ rslt = EclObject([]) @@ -1705,15 +1788,16 @@ def KChainComplexMorphism(morphism): EXAMPLES:: + sage: from sage.interfaces.kenzo import KChainComplexMorphism # optional - kenzo sage: C = ChainComplex({0: identity_matrix(ZZ, 1)}) sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) - sage: g = KChainComplexMorphism(f) # optional - kenzo - sage: g + sage: g = KChainComplexMorphism(f) # optional - kenzo + sage: g # optional - kenzo # random [K5 Morphism (degree 0): K1 -> K3] - sage: g.source_complex() # optional - kenzo + sage: g.source_complex() # optional - kenzo # random [K1 Chain-Complex] - sage: g.target_complex() # optional - kenzo + sage: g.target_complex() # optional - kenzo # random [K3 Chain-Complex] """ source = KChainComplex(morphism.domain()) @@ -1737,13 +1821,14 @@ def s2k_listofmorphisms(l): EXAMPLES:: + sage: from sage.interfaces.kenzo import s2k_listofmorphisms # optional - kenzo sage: C1 = ChainComplex({1: matrix(ZZ, 0, 2, [])}, degree_of_differential=-1) sage: C2 = ChainComplex({1: matrix(ZZ, 1, 2, [1, 0])},degree_of_differential=-1) sage: C3 = ChainComplex({0: matrix(ZZ, 0,2 , [])},degree_of_differential=-1) sage: M1 = Hom(C2,C1)({1: matrix(ZZ, 2, 2, [2, 0, 0, 2])}) sage: M2 = Hom(C3,C2)({0: matrix(ZZ, 1, 2, [2, 0])}) sage: l = [M1, M2] - sage: s2k_listofmorphisms(l) # optional - kenzo + sage: s2k_listofmorphisms(l) # optional - kenzo # random K3] [K17 Morphism (degree 0): K6 -> K1])> """ rslt = EclObject([]) @@ -1766,6 +1851,7 @@ def BicomplexSpectralSequence(l): EXAMPLES:: + sage: from sage.interfaces.kenzo import BicomplexSpectralSequence # optional - kenzo sage: C1 = ChainComplex({1: matrix(ZZ, 0, 2, [])}, degree_of_differential=-1) sage: C2 = ChainComplex({1: matrix(ZZ, 1, 2, [1, 0])},degree_of_differential=-1) sage: C3 = ChainComplex({0: matrix(ZZ, 0,2 , [])},degree_of_differential=-1) @@ -1780,7 +1866,7 @@ def BicomplexSpectralSequence(l): Z/2 + Z/4 0 0 0 0 Z sage: E.matrix(2,2,0) # optional - kenzo - [ 0 -4] [ 0 0] + [-4 0] """ return KenzoSpectralSequence(bicomplex_spectral_sequence(s2k_listofmorphisms(l))) From 811bd93f32ea5f2e1d50d9ac8793098fb1b250e5 Mon Sep 17 00:00:00 2001 From: jodivaso Date: Mon, 9 Dec 2019 11:36:06 +0100 Subject: [PATCH 289/476] doc cleanup --- src/sage/interfaces/kenzo.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index b48a853aabe..99dc692ce43 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -528,15 +528,15 @@ def null_morphism(self, target=None, degree=None): of degree ``degree``. INPUT: - + - ``target`` -- A KenzoChainComplex or None (default). - ``degree`` -- An integer number or None (default). OUTPUT: - A :class:`KenzoChainComplexMorphism` representing the null morphism between - ``self`` and ``target`` of degree ``degree``. If ``target`` takes None value, - ``self`` is assumed as the target chain complex; if ``degree`` takes None value, + ``self`` and ``target`` of degree ``degree``. If ``target`` takes None value, + ``self`` is assumed as the target chain complex; if ``degree`` takes None value, 0 is assumed as the degree of the null morphism. EXAMPLES:: @@ -621,7 +621,7 @@ def differential(self, dim=None, comb=None): ------------------------------------------------------------------------------ """ - if dim!=None and comb!=None: + if dim is not None and comb is not None: cmbn_list = pairing(comb) return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) else: @@ -750,7 +750,7 @@ def em_spectral_sequence(self): 0 0 0 0 0 """ if self.homology(1).invariants(): - raise ValueError("""Eilenberg-Moore spectral sequence implemented + raise ValueError("""Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets""") return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) @@ -1522,7 +1522,7 @@ def composite(self, object=None): def sum(self, object=None): r""" - Return a morphism, sum of the morphism ``self`` and the morphism(s) given + Return a morphism, sum of the morphism ``self`` and the morphism(s) given by the parameter ``object``. INPUT: @@ -1597,7 +1597,7 @@ def substract(self, object=None): - A :class:`KenzoChainComplexMorphism`, difference of the morphism ``self`` and the morphism(s) given by ``object`` (if ``object`` is None, ``self`` morphism is returned). - For example, if ``object`` = (mrph1, mrph2, mrph3) the result is + For example, if ``object`` = (mrph1, mrph2, mrph3) the result is ``self`` - mrph1 - mrph2 - mrph3. EXAMPLES:: From 89fc1dd71c6dcc2859ca3b19e6a6b59b33009a3e Mon Sep 17 00:00:00 2001 From: jodivaso Date: Mon, 9 Dec 2019 12:27:08 +0100 Subject: [PATCH 290/476] prefered ... instead of # random --- src/sage/interfaces/kenzo.py | 180 +++++++++++++++++------------------ 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 99dc692ce43..54b7fc361f1 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -545,17 +545,17 @@ def null_morphism(self, target=None, degree=None): sage: s2 = Sphere(2) # optional - kenzo sage: s3 = Sphere(3) # optional - kenzo sage: tp22 = s2.tensor_product(s2) # optional - kenzo - sage: tp22 # optional - kenzo # random - [K8 Chain-Complex] + sage: tp22 # optional - kenzo + [K... Chain-Complex] sage: tp23 = s2.tensor_product(s3) # optional - kenzo - sage: tp23 # optional - kenzo # random - [K11 Chain-Complex] + sage: tp23 # optional - kenzo + [K... Chain-Complex] sage: null1 = tp22.null_morphism() # optional - kenzo - sage: null1 # optional - kenzo # random - [K13 Morphism (degree 0): K8 -> K8] + sage: null1 # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: null2 = tp22.null_morphism(target = tp23, degree = -3) # optional - kenzo - sage: null2 # optional - kenzo # random - [K14 Morphism (degree -3): K8 -> K11] + sage: null2 # optional - kenzo + [K... Morphism (degree -3): K... -> K...] """ if target is None: target = self @@ -1278,13 +1278,13 @@ def source_complex(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo # random - [K2 Morphism (degree -1): K1 -> K1] - sage: differential_morphism.source_complex() # optional - kenzo # random - [K1 Chain-Complex] + sage: differential_morphism # optional - kenzo + [K... Morphism (degree -1): K... -> K...] + sage: differential_morphism.source_complex() # optional - kenzo + [K... Chain-Complex] """ return KenzoChainComplex(sorc_aux(self._kenzo)) @@ -1304,13 +1304,13 @@ def target_complex(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo # random - [K2 Morphism (degree -1): K1 -> K1] - sage: differential_morphism.target_complex() # optional - kenzo # random - [K1 Chain-Complex] + sage: differential_morphism # optional - kenzo + [K... Morphism (degree -1): K... -> K...] + sage: differential_morphism.target_complex() # optional - kenzo + [K... Chain-Complex] """ return KenzoChainComplex(trgt_aux(self._kenzo)) @@ -1330,11 +1330,11 @@ def degree(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo # random - [K2 Morphism (degree -1): K1 -> K1] + sage: differential_morphism # optional - kenzo + [K... Morphism (degree -1): K... -> K...] sage: differential_morphism.degree() # optional - kenzo -1 sage: differential_morphism.composite(differential_morphism).degree() # optional - kenzo @@ -1376,14 +1376,14 @@ def evaluation(self, dim, comb): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: differential_morphism = kenzo_chcm.differential() # optional - kenzo - sage: differential_morphism # optional - kenzo # random - [K2 Morphism (degree -1): K1 -> K1] + sage: differential_morphism # optional - kenzo + [K... Morphism (degree -1): K... -> K...] sage: dif_squared = differential_morphism.composite(differential_morphism) # optional - kenzo - sage: dif_squared # optional - kenzo # random - [K3 Morphism (degree -2): K1 -> K1] + sage: dif_squared # optional - kenzo + [K... Morphism (degree -2): K... -> K...] sage: kenzo_chcm.basis(5) # optional - kenzo ['G5G0', 'G5G1', 'G5G2'] sage: kenzo_chcm.differential(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo @@ -1447,14 +1447,14 @@ def opposite(self): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo # random - [K3 Morphism (degree 0): K1 -> K1] + sage: id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo # random - [K4 Morphism (degree 0): K1 -> K1] + sage: opps_id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: id.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1500,13 +1500,13 @@ def composite(self, object=None): sage: tp22 = s2.tensor_product(s2) # optional - kenzo sage: tp23 = s2.tensor_product(s3) # optional - kenzo sage: id = tp22.identity_morphism() # optional - kenzo - sage: id # optional - kenzo # random - [K13 Morphism (degree 0): K3 -> K3] + sage: id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: null = tp23.null_morphism(target = tp22, degree = 4) # optional - kenzo - sage: null # optional - kenzo # random - [K14 Morphism (degree 4): K11 -> K3] - sage: id.composite((tp22, null)) # optional - kenzo # random - [K15 Morphism (degree 3): K11 -> K3] + sage: null # optional - kenzo + [K... Morphism (degree 4): K... -> K...] + sage: id.composite((tp22, null)) # optional - kenzo + [K... Morphism (degree 3): K... -> K...] """ if object is None: return self @@ -1543,17 +1543,17 @@ def sum(self, object=None): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo # random - [K3 Morphism (degree 0): K1 -> K1] + sage: id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo # random - [K4 Morphism (degree 0): K1 -> K1] + sage: opps_id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: null = kenzo_chcm.null_morphism() # optional - kenzo - sage: null # optional - kenzo # random - [K5 Morphism (degree 0): K1 -> K1] + sage: null # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: idx2 = id.sum(id) # optional - kenzo sage: idx5 = idx2.sum((opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo @@ -1608,17 +1608,17 @@ def substract(self, object=None): sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo - sage: kenzo_chcm # optional - kenzo # random - [K1 Chain-Complex] + sage: kenzo_chcm # optional - kenzo + [K... Chain-Complex] sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo # random - [K3 Morphism (degree 0): K1 -> K1] + sage: id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: opps_id = id.opposite() # optional - kenzo - sage: opps_id # optional - kenzo # random - [K4 Morphism (degree 0): K1 -> K1] + sage: opps_id # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: null = kenzo_chcm.null_morphism() # optional - kenzo - sage: null # optional - kenzo # random - [K5 Morphism (degree 0): K1 -> K1] + sage: null # optional - kenzo + [K... Morphism (degree 0): K... -> K...] sage: idx2 = id.substract(opps_id) # optional - kenzo sage: opps_idx2 = idx2.substract((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo @@ -1671,23 +1671,23 @@ def change_source_target_complex(self, source=None, target=None): sage: from sage.interfaces.kenzo import Sphere, KenzoChainComplex # optional - kenzo sage: from sage.libs.ecl import ecl_eval sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo - sage: ZCC # optional - kenzo # random - [K1 Chain-Complex] + sage: ZCC # optional - kenzo + [K... Chain-Complex] sage: s2 = Sphere(2) # optional - kenzo sage: s3 = Sphere(3) # optional - kenzo sage: tp = s2.tensor_product(s3) # optional - kenzo - sage: tp # optional - kenzo # random - [K13 Chain-Complex] + sage: tp # optional - kenzo + [K... Filtered-Chain-Complex] sage: null = ZCC.null_morphism(tp) # optional - kenzo - sage: null # optional - kenzo # random - [K15 Morphism (degree 0): K1 -> K13] - sage: null.source_complex() # optional - kenzo # random - [K1 Chain-Complex] + sage: null # optional - kenzo + [K... Morphism (degree 0): K... -> K...] + sage: null.source_complex() # optional - kenzo + [K... Chain-Complex] sage: null2 = null.change_source_target_complex(source = tp) # optional - kenzo - sage: null2 # optional - kenzo # random - [K16 Morphism (degree 0): K13 -> K13] - sage: null2.source_complex() # optional - kenzo # random - [K13 Chain-Complex] + sage: null2 # optional - kenzo + [K... Morphism (degree 0): K... -> K...] + sage: null2.source_complex() # optional - kenzo + [K... Filtered-Chain-Complex] """ source = source or self.source_complex() target = target or self.target_complex() @@ -1715,22 +1715,22 @@ def destructive_change_source_target_complex(self, source=None, target=None): sage: from sage.interfaces.kenzo import Sphere, KenzoChainComplex # optional - kenzo sage: from sage.libs.ecl import ecl_eval sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo - sage: ZCC # optional - kenzo # random - [K1 Chain-Complex] + sage: ZCC # optional - kenzo + [K... Chain-Complex] sage: s2 = Sphere(2) # optional - kenzo sage: s3 = Sphere(3) # optional - kenzo sage: tp = s2.tensor_product(s3) # optional - kenzo - sage: tp # optional - kenzo # random - [K13 Chain-Complex] + sage: tp # optional - kenzo + [K... Filtered-Chain-Complex] sage: null = ZCC.null_morphism(tp) # optional - kenzo - sage: null # optional - kenzo # random - [K15 Morphism (degree 0): K1 -> K13] - sage: null.target_complex() # optional - kenzo # random - [K13 Chain-Complex] - sage: null.destructive_change_source_target_complex(target = ZCC) # optional - kenzo # random - [K15 Cohomology-Class on K1 of degree 0] - sage: null.target_complex() # optional - kenzo # random - [K1 Chain-Complex] + sage: null # optional - kenzo + [K... Morphism (degree 0): K... -> K...] + sage: null.target_complex() # optional - kenzo + [K... Filtered-Chain-Complex] + sage: null.destructive_change_source_target_complex(target = ZCC) # optional - kenzo + [K... Cohomology-Class on K... of degree 0] + sage: null.target_complex() # optional - kenzo + [K... Chain-Complex] """ source = source or self.source_complex() target = target or self.target_complex() @@ -1793,12 +1793,12 @@ def KChainComplexMorphism(morphism): sage: D = ChainComplex({0: zero_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: f = Hom(C,D)({0: identity_matrix(ZZ, 1), 1: zero_matrix(ZZ, 1)}) sage: g = KChainComplexMorphism(f) # optional - kenzo - sage: g # optional - kenzo # random - [K5 Morphism (degree 0): K1 -> K3] - sage: g.source_complex() # optional - kenzo # random - [K1 Chain-Complex] - sage: g.target_complex() # optional - kenzo # random - [K3 Chain-Complex] + sage: g # optional - kenzo + [K... Morphism (degree 0): K... -> K...] + sage: g.source_complex() # optional - kenzo + [K... Chain-Complex] + sage: g.target_complex() # optional - kenzo + [K... Chain-Complex] """ source = KChainComplex(morphism.domain()) target = KChainComplex(morphism.codomain()) @@ -1828,8 +1828,8 @@ def s2k_listofmorphisms(l): sage: M1 = Hom(C2,C1)({1: matrix(ZZ, 2, 2, [2, 0, 0, 2])}) sage: M2 = Hom(C3,C2)({0: matrix(ZZ, 1, 2, [2, 0])}) sage: l = [M1, M2] - sage: s2k_listofmorphisms(l) # optional - kenzo # random - K3] [K17 Morphism (degree 0): K6 -> K1])> + sage: s2k_listofmorphisms(l) # optional - kenzo + K...] [K... Morphism (degree 0): K... -> K...])> """ rslt = EclObject([]) for m in l: From 59e3d3a2daf62f4c5f83781315dbd7e382b22e46 Mon Sep 17 00:00:00 2001 From: jodivaso Date: Thu, 12 Dec 2019 18:51:53 +0100 Subject: [PATCH 291/476] tuned doc --- src/sage/interfaces/kenzo.py | 114 +++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 54b7fc361f1..326683d160a 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -628,6 +628,19 @@ def differential(self, dim=None, comb=None): return KenzoChainComplexMorphism(dffr_aux(self._kenzo)) def orgn(self): + r""" + Return the :orgn slot of Kenzo, which stores as a list the origin of the object + + EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere, loop_space # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: l2 = s2.loop_space() # optional - kenzo + sage: l2.orgn() # optional - kenzo + '(LOOP-SPACE [K... Simplicial-Set])' + sage: A = l2.cartesian_product(s2) # optional - kenzo + sage: A.orgn() + '(CRTS-PRDC [K... Simplicial-Group] [K... Simplicial-Set])' + """ return str(orgn_aux1(self._kenzo)) @@ -714,7 +727,7 @@ def homotopy_group(self, n): INPUT: - - ``n`` - the dimension of the homotopy group to be computed + - ``n`` -- the dimension of the homotopy group to be computed EXAMPLES:: @@ -725,7 +738,8 @@ def homotopy_group(self, n): Multiplicative Abelian group isomorphic to Z x Z """ if n not in ZZ or n < 2: - raise ValueError("homotopy groups can only be computed for dimensions greater than 1") + raise ValueError("""homotopy groups can only be computed + for dimensions greater than 1""") lgens = homotopy_list(self._kenzo, n).python() if lgens is not None: trgens = [0 if i == 1 else i for i in sorted(lgens)] @@ -737,6 +751,10 @@ def em_spectral_sequence(self): r""" Return the Eilenberg-Moore spectral sequence of ``self``. + OUTPUT: + + - A :class:`KenzoSpectralSequence` + EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere # optional - kenzo @@ -758,6 +776,10 @@ def sw_spectral_sequence(self): r""" Return the Serre sequence of the first step of the Whitehead tower. + OUTPUT: + + - A :class:`KenzoSpectralSequence` + EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere @@ -779,6 +801,10 @@ def serre_spectral_sequence(self): The object self must be created as a cartesian product (twisted or not). + OUTPUT: + + - A :class:`KenzoSpectralSequence` + EXAMPLES:: sage: from sage.interfaces.kenzo import Sphere @@ -903,6 +929,19 @@ def classifying_space(self): def k2s_matrix(kmatrix): r""" Convert an array of ECL to a matrix of Sage. + + INPUT: + + - ``kmatrix`` -- An array in ECL + + EXAMPLES:: + sage: from sage.interfaces.kenzo import k2s_matrix # optional - kenzo + sage: from sage.libs.ecl import EclObject + sage: M = EclObject("#2A((1 2 3) (3 2 1) (1 1 1))") + sage: k2s_matrix(M) # optional - kenzo + [1 2 3] + [3 2 1] + [1 1 1] """ dimensions = array_dimensions(kmatrix).python() kmatrix_list = make_array_to_lists(kmatrix).python() @@ -1038,7 +1077,7 @@ def SChainComplex(kchaincomplex, start=0, end=15): EXAMPLES:: - sage: from sage.interfaces.kenzo import KChainComplex, SChainComplex # optional - kenzo + sage: from sage.interfaces.kenzo import KChainComplex, SChainComplex # optional - kenzo sage: m1 = matrix(ZZ, 3, 2, [-1, 1, 3, -4, 5, 6]) sage: m4 = matrix(ZZ, 2, 2, [1, 2, 3, 6]) sage: m5 = matrix(ZZ, 2, 3, [2, 2, 2, -1, -1, -1]) @@ -1071,15 +1110,16 @@ def SAbstractSimplex(simplex, dim): EXAMPLES:: sage: from sage.libs.ecl import EclObject, ecl_eval - sage: from sage.interfaces.kenzo import KenzoObject, SAbstractSimplex # optional - kenzo - sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo - sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo - sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo - sage: SAbSm1.degeneracies() # optional - kenzo + sage: from sage.interfaces.kenzo import KenzoObject,\ + ....: SAbstractSimplex # optional - kenzo + sage: KAbSm = KenzoObject(ecl_eval("(ABSM 15 'K)")) # optional - kenzo + sage: SAbSm1 = SAbstractSimplex(KAbSm, 2) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 7) # optional - kenzo + sage: SAbSm1.degeneracies() # optional - kenzo [3, 2, 1, 0] - sage: SAbSm1.dimension() # optional - kenzo + sage: SAbSm1.dimension() # optional - kenzo 6 - sage: SAbSm2.dimension() # optional - kenzo + sage: SAbSm2.dimension() # optional - kenzo 11 """ degeneracies = dgop_int_ext(dgop(simplex._kenzo)).python() @@ -1106,13 +1146,14 @@ def KAbstractSimplex(simplex): EXAMPLES:: sage: from sage.homology.simplicial_set import AbstractSimplex - sage: from sage.interfaces.kenzo import KAbstractSimplex, SAbstractSimplex # optional - kenzo - sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo - sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo - sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo - sage: SAbSm.degeneracies() == SAbSm2.degeneracies() # optional - kenzo + sage: from sage.interfaces.kenzo import KAbstractSimplex,\ + ....: SAbstractSimplex # optional - kenzo + sage: SAbSm = AbstractSimplex(1, (2,0,3,2,1), name = 'SAbSm') # optional - kenzo + sage: KAbSm = KAbstractSimplex(SAbSm) # optional - kenzo + sage: SAbSm2 = SAbstractSimplex(KAbSm, 1) # optional - kenzo + sage: SAbSm.degeneracies() == SAbSm2.degeneracies() # optional - kenzo True - sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo + sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), @@ -1142,7 +1183,8 @@ def KFiniteSimplicialSet(sset): sage: s02 = AbstractSimplex(1, name='s02') sage: s12 = AbstractSimplex(1, name='s12') sage: s012 = AbstractSimplex(2, name='s012') - sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) + sage: Triangle = SimplicialSet({s01: (s1, s0),\ + ....: s02: (s2, s0), s12: (s2, s1)}, base_point = s0) sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo sage: KTriangle.homology(1) # optional - kenzo Z @@ -1201,7 +1243,8 @@ def SFiniteSimplicialSet(ksimpset, limit): EXAMPLES:: sage: from sage.homology.simplicial_set import SimplicialSet - sage: from sage.interfaces.kenzo import AbstractSimplex, KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo + sage: from sage.interfaces.kenzo import AbstractSimplex,\ + ....: KFiniteSimplicialSet, SFiniteSimplicialSet, Sphere # optional - kenzo sage: s0 = AbstractSimplex(0, name='s0') # optional - kenzo sage: s1 = AbstractSimplex(0, name='s1') # optional - kenzo sage: s2 = AbstractSimplex(0, name='s2') # optional - kenzo @@ -1209,7 +1252,8 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: s02 = AbstractSimplex(1, name='s02') # optional - kenzo sage: s12 = AbstractSimplex(1, name='s12') # optional - kenzo sage: s012 = AbstractSimplex(2, name='s012') # optional - kenzo - sage: Triangle = SimplicialSet({s01: (s1, s0), s02: (s2, s0), s12: (s2, s1)}, base_point = s0) # optional - kenzo + sage: Triangle = SimplicialSet({s01: (s1, s0),\ + ....: s02: (s2, s0), s12: (s2, s1)}, base_point = s0) # optional - kenzo sage: KTriangle = KFiniteSimplicialSet(Triangle) # optional - kenzo sage: STriangle = SFiniteSimplicialSet(KTriangle, 1) # optional - kenzo sage: STriangle.homology() # optional - kenzo @@ -1223,8 +1267,9 @@ def SFiniteSimplicialSet(ksimpset, limit): """ list_orgn = orgn_aux1(ksimpset._kenzo).python() if nth(0, list_orgn).python()[0] == 'CRTS-PRDC': - return SFiniteSimplicialSet(KenzoSimplicialSet(nth(1, list_orgn)), - limit).cartesian_product(SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) + return SFiniteSimplicialSet( + KenzoSimplicialSet(nth(1, list_orgn)), limit).cartesian_product( + SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) rslt = {} simplices = [] faces = [] @@ -1344,9 +1389,6 @@ def degree(self): """ return degr_aux(self._kenzo).python() - def orgn(self): - return str(orgn_aux1(self._kenzo)) - def evaluation(self, dim, comb): r""" Apply the morphism on a combination ``comb`` of dimension ``dim``. @@ -1354,6 +1396,7 @@ def evaluation(self, dim, comb): INPUT: - ``dim`` -- An integer number + - ``comb`` -- A list representing a formal sum of generators in the module of dimension ``dim``. For example, to represent G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. Note that the @@ -1555,7 +1598,8 @@ def sum(self, object=None): sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: idx2 = id.sum(id) # optional - kenzo - sage: idx5 = idx2.sum((opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo + sage: idx5 = idx2.sum(\ + ....: (opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1620,7 +1664,8 @@ def substract(self, object=None): sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: idx2 = id.substract(opps_id) # optional - kenzo - sage: opps_idx2 = idx2.substract((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo + sage: opps_idx2 = idx2.substract\ + ....: ((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1650,8 +1695,8 @@ def substract(self, object=None): def change_source_target_complex(self, source=None, target=None): r""" - Build, from the morphism ``self``, a new morphism with ``source`` and ``target`` as source - and target Kenzo chain complexes, respectively. + Build, from the morphism ``self``, a new morphism with ``source`` + and ``target`` as source and target Kenzo chain complexes, respectively. INPUT: @@ -1661,10 +1706,12 @@ def change_source_target_complex(self, source=None, target=None): OUTPUT: - - A :class:`KenzoChainComplexMorphism` inheriting from ``self`` the degree (:degr slot in Kenzo), - the algorithm (:intr slot in Kenzo) and the strategy (:strt slot in Kenzo). The source and - target slots of this new morphism are given by the parameters ``source`` and ``target`` - respectively; if any parameter is ommited, the corresponding slot is inherited from ``self``. + - A :class:`KenzoChainComplexMorphism` inheriting from ``self`` the + degree (:degr slot in Kenzo), the algorithm (:intr slot in Kenzo) + and the strategy (:strt slot in Kenzo). The source and target slots + of this new morphism are given by the parameters ``source`` and + ``target`` respectively; if any parameter is ommited, the corresponding + slot is inherited from ``self``. EXAMPLES:: @@ -1691,7 +1738,8 @@ def change_source_target_complex(self, source=None, target=None): """ source = source or self.source_complex() target = target or self.target_complex() - return KenzoChainComplexMorphism(change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism( + change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) def destructive_change_source_target_complex(self, source=None, target=None): r""" From 8c3c3ed6ddeb26ee85313440b315682f862eb7c9 Mon Sep 17 00:00:00 2001 From: jodivaso Date: Sun, 15 Dec 2019 11:29:32 +0100 Subject: [PATCH 292/476] fixed missing empty lines after EXAMPLES:: and added doc for build_morphism function --- src/sage/interfaces/kenzo.py | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 326683d160a..063211aaed7 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -632,6 +632,7 @@ def orgn(self): Return the :orgn slot of Kenzo, which stores as a list the origin of the object EXAMPLES:: + sage: from sage.interfaces.kenzo import Sphere, loop_space # optional - kenzo sage: s2 = Sphere(2) # optional - kenzo sage: l2 = s2.loop_space() # optional - kenzo @@ -935,6 +936,7 @@ def k2s_matrix(kmatrix): - ``kmatrix`` -- An array in ECL EXAMPLES:: + sage: from sage.interfaces.kenzo import k2s_matrix # optional - kenzo sage: from sage.libs.ecl import EclObject sage: M = EclObject("#2A((1 2 3) (3 2 1) (1 1 1))") @@ -988,6 +990,7 @@ def s2k_dictmat(sdictmat): - A :class:`EclObject` EXAMPLES:: + sage: from sage.interfaces.kenzo import s2k_dictmat # optional - kenzo sage: A = Matrix([[1,2,3],[3,2,1],[1,1,1]]) sage: B = Matrix([[1,2],[2,1],[1,1]]) @@ -1015,6 +1018,7 @@ def pairing(slist): - A :class:`EclObject` EXAMPLES:: + sage: from sage.interfaces.kenzo import pairing # optional - kenzo sage: l = [1,2,3] sage: pairing(l) # optional - kenzo @@ -1787,6 +1791,47 @@ def destructive_change_source_target_complex(self, source=None, target=None): def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): + r""" + Build a morphism of chain complexes by means of the corresponding build-mrph Kenzo + function. + + INPUT: + + - ``source_complex`` -- The source object as a KenzoChainComplex instance + + - ``target_complex`` -- The target object as a KenzoChainComplex instance + + - ``degree`` -- An integer number representing the degree of the morphism + + - ``algorithm`` -- A Lisp function defining the mapping (:intr slot in Kenzo) + + - ``strategy`` -- The strategy (:strt slot in Kenzo), which must be one of + the two strings ``gnrt`` or ``cmbn``, depending if the ``algorithm`` (a Lisp + function) uses as arguments a degree and a generator or a combination, + respectively. + + - ``orgn`` -- A list containing a description about the origin of the morphism + + OUTPUT: + + - A :class:`KenzoChainComplexMorphism` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import KenzoChainComplex,\ + ....: build_morphism # optional - kenzo + sage: from sage.libs.ecl import ecl_eval + sage: ZCC = KenzoChainComplex(ecl_eval("(z-chcm)")) # optional - kenzo + sage: A = build_morphism(ZCC, ZCC, -1,\ + ....: ecl_eval("#'(lambda (comb) (cmbn (1- (degr comb))))"),\ + ....: "cmbn", ["zero morphism on ZCC"]) # optional - kenzo + sage: A.target_complex() # optional - kenzo + [K... Chain-Complex] + sage: A.degree() # optional - kenzo + -1 + sage: type(A) # optional - kenzo + + """ return KenzoChainComplexMorphism( build_mrph_aux(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) From 7dbf0ac85cbc0dff856c024ee889296ed33b36aa Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Tue, 17 Dec 2019 15:52:38 +0100 Subject: [PATCH 293/476] Fix optional doctest --- src/sage/interfaces/kenzo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 063211aaed7..7037684ff08 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -639,7 +639,7 @@ def orgn(self): sage: l2.orgn() # optional - kenzo '(LOOP-SPACE [K... Simplicial-Set])' sage: A = l2.cartesian_product(s2) # optional - kenzo - sage: A.orgn() + sage: A.orgn() # optional - kenzo '(CRTS-PRDC [K... Simplicial-Group] [K... Simplicial-Set])' """ return str(orgn_aux1(self._kenzo)) From c33f77f4f9598fee4c3fb62e969faebbcf92cc43 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Tue, 17 Dec 2019 16:02:52 +0100 Subject: [PATCH 294/476] New version of kenzo --- build/pkgs/kenzo/checksums.ini | 8 ++++---- build/pkgs/kenzo/package-version.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/kenzo/checksums.ini b/build/pkgs/kenzo/checksums.ini index abd092f806f..f4068e4588d 100644 --- a/build/pkgs/kenzo/checksums.ini +++ b/build/pkgs/kenzo/checksums.ini @@ -1,4 +1,4 @@ -tarball=kenzo-1.1.7-r3.tar.gz -sha1=92433fee5f83d575483bbbd9730c2cb094c292a4 -md5=7dc2207eb8071a2710df825ac9409324 -cksum=3315029495 +tarball=kenzo-1.1.8.tar.gz +sha1=365185b1c3373060bd7124937aad13c3df82b4b7 +md5=7cd942e5c725327624266a4cf094113c +cksum=2540973636 diff --git a/build/pkgs/kenzo/package-version.txt b/build/pkgs/kenzo/package-version.txt index 6ba101eb19d..18efdb9ae67 100644 --- a/build/pkgs/kenzo/package-version.txt +++ b/build/pkgs/kenzo/package-version.txt @@ -1 +1 @@ -1.1.7-r3 +1.1.8 From 87c4242c67a8e0cb9407c662007afab247d6f8dd Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 18 Dec 2019 13:00:10 +0100 Subject: [PATCH 295/476] Some review changes --- src/doc/en/reference/interfaces/index.rst | 1 + src/sage/interfaces/kenzo.py | 335 +++++++++++----------- 2 files changed, 169 insertions(+), 167 deletions(-) diff --git a/src/doc/en/reference/interfaces/index.rst b/src/doc/en/reference/interfaces/index.rst index 8680b94deb8..95a8678b071 100644 --- a/src/doc/en/reference/interfaces/index.rst +++ b/src/doc/en/reference/interfaces/index.rst @@ -76,6 +76,7 @@ and testing to make sure nothing funny is going on). sage/interfaces/gp sage/interfaces/jmoldata sage/interfaces/kash + sage/interfaces/kenzo sage/interfaces/latte sage/interfaces/lie sage/interfaces/lisp diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 7037684ff08..05ae36a5176 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -39,8 +39,12 @@ from sage.homology.simplicial_set import AbstractSimplex, SimplicialSet from sage.libs.ecl import EclObject, ecl_eval, EclListIterator +from sage.misc.package import installed_packages, PackageNotFoundError +if not 'kenzo' in installed_packages(): + raise PackageNotFoundError('kenzo') + # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we # also do it here for redundancy. @@ -57,66 +61,63 @@ # defining the auxiliary functions as wrappers over the kenzo ones -chcm_mat = EclObject("chcm-mat") -homologie = EclObject("homologie") -sphere = EclObject("sphere") -crts_prdc = EclObject("crts-prdc") -moore = EclObject("moore") -k_z = EclObject("k-z") -k_z2 = EclObject("k-z2") -k_zp = EclObject("k-zp") -echcm = EclObject("echcm") -loop_space = EclObject("loop-space") -tnsr_prdc = EclObject("tnsr-prdc") -typep = EclObject("typep") -classifying_space = EclObject("classifying-space") -suspension = EclObject("suspension") -homotopy_list = EclObject("homotopy-list") -nth = EclObject("nth") -entry = EclObject("entry") -nlig = EclObject("nlig") -ncol = EclObject("ncol") -array_dimensions = EclObject("array-dimensions") -convertmatrice = EclObject("convertmatrice") -make_array_to_lists = EclObject("make-array-to-lists") -make_array_from_lists = EclObject("make-array-from-lists") -chcm_mat2 = EclObject("chcm-mat2") -build_finite_ss2 = EclObject("build-finite-ss2") -gmsm = EclObject("gmsm") -dgop = EclObject("dgop") -dgop_ext_int = EclObject("dgop-ext-int") -dgop_int_ext = EclObject("dgop-int-ext") -basis_aux1 = EclObject("basis_aux1") -orgn_aux1 = EclObject("orgn_aux1") -dffr_aux1 = EclObject("dffr_aux1") -kabstractsimplex_aux1 = EclObject("kabstractsimplex_aux1") -kchaincomplex_aux1 = EclObject("kchaincomplex_aux1") -sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") -spectral_sequence_group = EclObject("spectral-sequence-group") -spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") -eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") -serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") -serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") -wedge = EclObject("wedge") -join = EclObject("join") -kmorphismchaincomplex_aux1 = EclObject("kmorphismchaincomplex_aux1") -bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") -nreverse = EclObject("nreverse") -smash_product = EclObject("smash-product") -build_mrph_aux = EclObject("build-mrph-aux") -zero_mrph = EclObject("zero-mrph") -idnt_mrph = EclObject("idnt-mrph") -dffr_aux = EclObject("dffr-aux") -sorc_aux = EclObject("sorc-aux") -trgt_aux = EclObject("trgt-aux") -degr_aux = EclObject("degr-aux") -evaluation_aux1 = EclObject("evaluation-aux1") -opps = EclObject("opps") -cmps = EclObject("cmps") -add = EclObject("add") -sbtr = EclObject("sbtr") -change_sorc_trgt_aux = EclObject("change-sorc-trgt-aux") -dstr_change_sorc_trgt_aux = EclObject("dstr-change-sorc-trgt-aux") +_chcm_mat = EclObject("chcm-mat") +_homologie = EclObject("homologie") +_sphere = EclObject("sphere") +_crts_prdc = EclObject("crts-prdc") +_moore = EclObject("moore") +_k_z = EclObject("k-z") +_k_z2 = EclObject("k-z2") +_k_zp = EclObject("k-zp") +_echcm = EclObject("echcm") +_loop_space = EclObject("loop-space") +_tnsr_prdc = EclObject("tnsr-prdc") +_classifying_space = EclObject("classifying-space") +_suspension = EclObject("suspension") +_homotopy_list = EclObject("homotopy-list") +_nth = EclObject("nth") +_nlig = EclObject("nlig") +_ncol = EclObject("ncol") +_array_dimensions = EclObject("array-dimensions") +_convertmatrice = EclObject("convertmatrice") +_make_array_to_lists = EclObject("make-array-to-lists") +_make_array_from_lists = EclObject("make-array-from-lists") +_chcm_mat2 = EclObject("chcm-mat2") +_build_finite_ss2 = EclObject("build-finite-ss2") +_gmsm = EclObject("gmsm") +_dgop = EclObject("dgop") +_dgop_int_ext = EclObject("dgop-int-ext") +_basis_aux1 = EclObject("basis_aux1") +_orgn_aux1 = EclObject("orgn_aux1") +_dffr_aux1 = EclObject("dffr_aux1") +_kabstractsimplex_aux1 = EclObject("kabstractsimplex_aux1") +_kchaincomplex_aux1 = EclObject("kchaincomplex_aux1") +_sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") +_spectral_sequence_group = EclObject("spectral-sequence-group") +_spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") +_eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") +_serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") +_serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") +_wedge = EclObject("wedge") +_join = EclObject("join") +_kmorphismchaincomplex_aux1 = EclObject("kmorphismchaincomplex_aux1") +_bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") +_nreverse = EclObject("nreverse") +_smash_product = EclObject("smash-product") +_build_mrph_aux = EclObject("build-mrph-aux") +_zero_mrph = EclObject("zero-mrph") +_idnt_mrph = EclObject("idnt-mrph") +_dffr_aux = EclObject("dffr-aux") +_sorc_aux = EclObject("sorc-aux") +_trgt_aux = EclObject("trgt-aux") +_degr_aux = EclObject("degr-aux") +_evaluation_aux1 = EclObject("evaluation-aux1") +_opps = EclObject("opps") +_cmps = EclObject("cmps") +_add = EclObject("add") +_sbtr = EclObject("sbtr") +_change_sorc_trgt_aux = EclObject("change-sorc-trgt-aux") +_dstr_change_sorc_trgt_aux = EclObject("dstr-change-sorc-trgt-aux") def Sphere(n): @@ -140,7 +141,7 @@ def Sphere(n): sage: [s2.homology(i) for i in range(8)] # optional - kenzo [Z, 0, Z, 0, 0, 0, 0, 0] """ - kenzosphere = sphere(n) + kenzosphere = _sphere(n) return KenzoSimplicialSet(kenzosphere) @@ -171,7 +172,7 @@ def MooreSpace(m, n): sage: [m24.homology(i) for i in range(8)] # optional - kenzo [Z, 0, 0, 0, C2, 0, 0, 0] """ - kenzomoore = moore(m, n) + kenzomoore = _moore(m, n) return KenzoSimplicialSet(kenzomoore) @@ -204,13 +205,13 @@ def EilenbergMacLaneSpace(G, n): [Z, 0, 0, C2, 0, C2, C2, C2] """ if G == ZZ: - kenzospace = k_z(n) + kenzospace = _k_z(n) return KenzoSimplicialGroup(kenzospace) elif G == AdditiveAbelianGroup([2]): - kenzospace = k_z2(n) + kenzospace = _k_z2(n) return KenzoSimplicialGroup(kenzospace) elif G in CommutativeAdditiveGroups() and G.is_cyclic(): - kenzospace = k_zp(G.cardinality(), n) + kenzospace = _k_zp(G.cardinality(), n) return KenzoSimplicialGroup(kenzospace) else: raise NotImplementedError("Eilenberg-MacLane spaces are only supported over ZZ and ZZ_n") @@ -233,8 +234,8 @@ def __init__(self, kenzo_object): TESTS:: sage: from sage.interfaces.kenzo import KenzoObject # optional -kenzo - sage: from sage.interfaces.kenzo import sphere # optional -kenzo - sage: ks = sphere(2) # optional -kenzo + sage: from sage.interfaces.kenzo import _sphere # optional -kenzo + sage: ks = _sphere(2) # optional -kenzo sage: ks # optional -kenzo sage: s2 = KenzoObject(ks) # optional -kenzo @@ -290,7 +291,7 @@ def group(self, p, i, j): sage: EMS.group(0, -1, 3) # optional - kenzo Trivial group """ - invs = spectral_sequence_group(self._kenzo, p, i, j).python() + invs = _spectral_sequence_group(self._kenzo, p, i, j).python() if not invs: invs = [] return AdditiveAbelianGroup(invs) @@ -324,7 +325,7 @@ def matrix(self, p, i, j): [ 3 0 -3] [ 0 2 -3] """ - klist = spectral_sequence_differential_matrix(self._kenzo, p, i, j) + klist = _spectral_sequence_differential_matrix(self._kenzo, p, i, j) plist = klist.python() if plist is None or plist == [None]: i = len(self.group(p, i, j).invariants()) @@ -433,10 +434,10 @@ def homology(self, n): sage: s2.homology(2) # optional - kenzo Z """ - echcm1 = echcm(self._kenzo) - m1 = chcm_mat(echcm1, n) - m2 = chcm_mat(echcm1, n + 1) - homology = homologie(m1, m2) + echcm1 = _echcm(self._kenzo) + m1 = _chcm_mat(echcm1, n) + m2 = _chcm_mat(echcm1, n + 1) + homology = _homologie(m1, m2) lhomomology = [i for i in EclListIterator(homology)] res = [] for component in lhomomology: @@ -467,7 +468,7 @@ def tensor_product(self, other): sage: [p.homology(i) for i in range(8)] # optional - kenzo [Z, 0, Z, Z, 0, Z, 0, 0] """ - return KenzoChainComplex(tnsr_prdc(self._kenzo, other._kenzo)) + return KenzoChainComplex(_tnsr_prdc(self._kenzo, other._kenzo)) def basis(self, dim): r""" @@ -501,7 +502,7 @@ def basis(self, dim): Basis in dimension 5: ['G5G0', 'G5G1', 'G5G2'] """ - return basis_aux1(self._kenzo, dim).python() + return _basis_aux1(self._kenzo, dim).python() def identity_morphism(self): r""" @@ -516,11 +517,11 @@ def identity_morphism(self): sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: s2 = Sphere(2) # optional - kenzo sage: tp = s2.tensor_product(s2) # optional - kenzo - sage: id = tp.identity_morphism() # optional - kenzo - sage: type(id) # optional - kenzo + sage: idnt = tp.identity_morphism() # optional - kenzo + sage: type(idnt) # optional - kenzo """ - return KenzoChainComplexMorphism(idnt_mrph(self._kenzo)) + return KenzoChainComplexMorphism(_idnt_mrph(self._kenzo)) def null_morphism(self, target=None, degree=None): r""" @@ -535,9 +536,9 @@ def null_morphism(self, target=None, degree=None): OUTPUT: - A :class:`KenzoChainComplexMorphism` representing the null morphism between - ``self`` and ``target`` of degree ``degree``. If ``target`` takes None value, - ``self`` is assumed as the target chain complex; if ``degree`` takes None value, - 0 is assumed as the degree of the null morphism. + ``self`` and ``target`` of degree ``degree``. If ``target`` takes None value, + ``self`` is assumed as the target chain complex; if ``degree`` takes None value, + 0 is assumed as the degree of the null morphism. EXAMPLES:: @@ -566,7 +567,7 @@ def null_morphism(self, target=None, degree=None): elif (not degree == 0) and (not degree.is_integer()): raise ValueError("'degree' parameter must be an Integer number") else: - return KenzoChainComplexMorphism(zero_mrph(self._kenzo, target._kenzo, degree)) + return KenzoChainComplexMorphism(_zero_mrph(self._kenzo, target._kenzo, degree)) def differential(self, dim=None, comb=None): r""" @@ -577,20 +578,20 @@ def differential(self, dim=None, comb=None): - ``dim`` -- An integer number or None (default) - ``comb`` -- A list representing a formal sum of generators in the module - of dimension ``dim`` or None (default). For example, to represent - G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. - Note that the generators must be in ascending order respect to the number - after the second G in their representation; the parameter - ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in - Kenzo. + of dimension ``dim`` or None (default). For example, to represent + G7G12 + 3*G7G0 - 5*G7G3 we use the list [3, 'G7G0', -5, 'G7G3', 1, 'G7G12']. + Note that the generators must be in ascending order respect to the number + after the second G in their representation; the parameter + ``comb`` = [1, 'G7G12', 3, 'G7G0', -5, 'G7G3'] will produce an error in + Kenzo. OUTPUT: - If ``dim`` and ``comb`` are not None, it returns a Kenzo combination - representing the differential of the formal combination represented by - ``comb`` in the chain complex ``self`` in dimension ``dim``. On the other - hand, if `dim`` or ``comb`` (or both) take None value, the differential - :class:`KenzoMorphismChainComplex` of ``self`` is returned. + representing the differential of the formal combination represented by + ``comb`` in the chain complex ``self`` in dimension ``dim``. On the other + hand, if `dim`` or ``comb`` (or both) take None value, the differential + :class:`KenzoMorphismChainComplex` of ``self`` is returned. EXAMPLES:: @@ -623,9 +624,9 @@ def differential(self, dim=None, comb=None): """ if dim is not None and comb is not None: cmbn_list = pairing(comb) - return KenzoObject(dffr_aux1(self._kenzo, dim, cmbn_list)) + return KenzoObject(_dffr_aux1(self._kenzo, dim, cmbn_list)) else: - return KenzoChainComplexMorphism(dffr_aux(self._kenzo)) + return KenzoChainComplexMorphism(_dffr_aux(self._kenzo)) def orgn(self): r""" @@ -633,7 +634,7 @@ def orgn(self): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere, loop_space # optional - kenzo + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: s2 = Sphere(2) # optional - kenzo sage: l2 = s2.loop_space() # optional - kenzo sage: l2.orgn() # optional - kenzo @@ -642,7 +643,7 @@ def orgn(self): sage: A.orgn() # optional - kenzo '(CRTS-PRDC [K... Simplicial-Group] [K... Simplicial-Set])' """ - return str(orgn_aux1(self._kenzo)) + return str(_orgn_aux1(self._kenzo)) class KenzoSimplicialSet(KenzoChainComplex): @@ -674,7 +675,7 @@ def loop_space(self, n=1): sage: [l2.homology(i) for i in range(8)] # optional - kenzo [Z, Z, Z, Z, Z, Z, Z, Z] """ - return KenzoSimplicialGroup(loop_space(self._kenzo, n)) + return KenzoSimplicialGroup(_loop_space(self._kenzo, n)) def cartesian_product(self, other): r""" @@ -699,7 +700,7 @@ def cartesian_product(self, other): sage: [p.homology(i) for i in range(6)] # optional - kenzo [Z, 0, Z, Z, 0, Z] """ - prod_kenzo = crts_prdc(self._kenzo, other._kenzo) + prod_kenzo = _crts_prdc(self._kenzo, other._kenzo) return KenzoSimplicialSet(prod_kenzo) def suspension(self): @@ -720,7 +721,7 @@ def suspension(self): sage: [s.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, Z, 0] """ - return KenzoSimplicialSet(suspension(self._kenzo)) + return KenzoSimplicialSet(_suspension(self._kenzo)) def homotopy_group(self, n): """ @@ -741,7 +742,7 @@ def homotopy_group(self, n): if n not in ZZ or n < 2: raise ValueError("""homotopy groups can only be computed for dimensions greater than 1""") - lgens = homotopy_list(self._kenzo, n).python() + lgens = _homotopy_list(self._kenzo, n).python() if lgens is not None: trgens = [0 if i == 1 else i for i in sorted(lgens)] return AbelianGroup(trgens) @@ -771,7 +772,7 @@ def em_spectral_sequence(self): if self.homology(1).invariants(): raise ValueError("""Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets""") - return KenzoSpectralSequence(eilenberg_moore_spectral_sequence(self._kenzo)) + return KenzoSpectralSequence(_eilenberg_moore_spectral_sequence(self._kenzo)) def sw_spectral_sequence(self): r""" @@ -794,7 +795,7 @@ def sw_spectral_sequence(self): 0 0 0 0 0 Z 0 0 Z 0 """ - return KenzoSpectralSequence(serre_whitehead_spectral_sequence(self._kenzo)) + return KenzoSpectralSequence(_serre_whitehead_spectral_sequence(self._kenzo)) def serre_spectral_sequence(self): r""" @@ -819,7 +820,7 @@ def serre_spectral_sequence(self): 0 0 0 Z 0 Z """ - return KenzoSpectralSequence(serre_spectral_sequence_product(self._kenzo)) + return KenzoSpectralSequence(_serre_spectral_sequence_product(self._kenzo)) def wedge(self, other): r""" @@ -844,7 +845,7 @@ def wedge(self, other): sage: [w.homology(i) for i in range(6)] # optional - kenzo [Z, 0, Z, Z, 0, 0] """ - wedge_kenzo = wedge(self._kenzo, other._kenzo) + wedge_kenzo = _wedge(self._kenzo, other._kenzo) return KenzoSimplicialSet(wedge_kenzo) def join(self, other): @@ -870,7 +871,7 @@ def join(self, other): sage: [j.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, 0, 0] """ - join_kenzo = join(self._kenzo, other._kenzo) + join_kenzo = _join(self._kenzo, other._kenzo) return KenzoSimplicialSet(join_kenzo) def smash_product(self, other): @@ -896,7 +897,7 @@ def smash_product(self, other): sage: [s.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, 0, Z] """ - smash_kenzo = smash_product(self._kenzo, other._kenzo) + smash_kenzo = _smash_product(self._kenzo, other._kenzo) return KenzoSimplicialSet(smash_kenzo) @@ -924,7 +925,7 @@ def classifying_space(self): sage: [c.homology(i) for i in range(8)] # optional - kenzo [Z, 0, 0, 0, C2, 0, 0, 0] """ - return KenzoSimplicialGroup(classifying_space(self._kenzo)) + return KenzoSimplicialGroup(_classifying_space(self._kenzo)) def k2s_matrix(kmatrix): @@ -945,8 +946,8 @@ def k2s_matrix(kmatrix): [3 2 1] [1 1 1] """ - dimensions = array_dimensions(kmatrix).python() - kmatrix_list = make_array_to_lists(kmatrix).python() + dimensions = _array_dimensions(kmatrix).python() + kmatrix_list = _make_array_to_lists(kmatrix).python() return matrix(dimensions[0], dimensions[1], kmatrix_list) @@ -973,7 +974,7 @@ def s2k_matrix(smatrix): dimensions = smatrix.dimensions() for i in smatrix.rows(): initcontents.append(i.list()) - return make_array_from_lists(dimensions[0], dimensions[1], initcontents) + return _make_array_from_lists(dimensions[0], dimensions[1], initcontents) def s2k_dictmat(sdictmat): @@ -1059,7 +1060,7 @@ def KChainComplex(chain_complex): d = chain_complex.differential() chcm = s2k_dictmat(d) str_orgn = str(d)[1:-1].replace(":", " ").replace(" ", ".").replace("\n", "").replace(",", "") - return KenzoChainComplex(kchaincomplex_aux1(chcm, str_orgn)) + return KenzoChainComplex(_kchaincomplex_aux1(chcm, str_orgn)) def SChainComplex(kchaincomplex, start=0, end=15): @@ -1091,9 +1092,9 @@ def SChainComplex(kchaincomplex, start=0, end=15): """ matrices = {} for i in range(start, end): - dffr_i = chcm_mat2(kchaincomplex._kenzo, i) - if ((nlig(dffr_i).python() != 0) and (ncol(dffr_i).python() != 0)): - matrices[i] = k2s_matrix(convertmatrice(dffr_i)) + dffr_i = _chcm_mat2(kchaincomplex._kenzo, i) + if ((_nlig(dffr_i).python() != 0) and (_ncol(dffr_i).python() != 0)): + matrices[i] = k2s_matrix(_convertmatrice(dffr_i)) return ChainComplex(matrices, degree=-1) @@ -1126,12 +1127,12 @@ def SAbstractSimplex(simplex, dim): sage: SAbSm2.dimension() # optional - kenzo 11 """ - degeneracies = dgop_int_ext(dgop(simplex._kenzo)).python() + degeneracies = _dgop_int_ext(_dgop(simplex._kenzo)).python() if degeneracies is None: degeneracies = [] else: degeneracies = tuple(degeneracies) - name = gmsm(simplex._kenzo).python() + name = _gmsm(simplex._kenzo).python() return AbstractSimplex(dim, degeneracies, name=name) @@ -1160,7 +1161,7 @@ def KAbstractSimplex(simplex): sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ - return KenzoObject(kabstractsimplex_aux1(simplex.degeneracies(), + return KenzoObject(_kabstractsimplex_aux1(simplex.degeneracies(), 's' + str(hash(simplex)))) @@ -1226,7 +1227,7 @@ def KFiniteSimplicialSet(sset): degen_z.append(name) auxiliar_list.append(degen_z) list_rslt.append(auxiliar_list) - return KenzoSimplicialSet(build_finite_ss2(list_rslt)) + return KenzoSimplicialSet(_build_finite_ss2(list_rslt)) def SFiniteSimplicialSet(ksimpset, limit): @@ -1269,23 +1270,23 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: SS1vS3.homology() # optional - kenzo {0: 0, 1: Z, 2: 0, 3: Z} """ - list_orgn = orgn_aux1(ksimpset._kenzo).python() - if nth(0, list_orgn).python()[0] == 'CRTS-PRDC': + list_orgn = _orgn_aux1(ksimpset._kenzo).python() + if _nth(0, list_orgn).python()[0] == 'CRTS-PRDC': return SFiniteSimplicialSet( - KenzoSimplicialSet(nth(1, list_orgn)), limit).cartesian_product( - SFiniteSimplicialSet(KenzoSimplicialSet(nth(2, list_orgn)), limit)) + KenzoSimplicialSet(_nth(1, list_orgn)), limit).cartesian_product( + SFiniteSimplicialSet(KenzoSimplicialSet(_nth(2, list_orgn)), limit)) rslt = {} simplices = [] faces = [] bases = [] names = [] for k in range(limit + 1): - basis_k = basis_aux1(ksimpset._kenzo, k) + basis_k = _basis_aux1(ksimpset._kenzo, k) names_k = ksimpset.basis(k) lbasis_k = [AbstractSimplex(k, name=i) for i in EclListIterator(basis_k)] bases.append(lbasis_k) names.append(names_k) - all_simplices = sfinitesimplicialset_aux1(ksimpset._kenzo, limit) + all_simplices = _sfinitesimplicialset_aux1(ksimpset._kenzo, limit) lall_simplices = [i for i in EclListIterator(all_simplices)] dim = 1 for Kdim in lall_simplices: @@ -1293,10 +1294,10 @@ def SFiniteSimplicialSet(ksimpset, limit): index1 = names[dim].index(str(simp.car())) lKdim_cdr = [] for i in EclListIterator(simp.cdr()): - degenop = dgop_int_ext(dgop(i)).python() + degenop = _dgop_int_ext(_dgop(i)).python() if degenop is None: degenop = [] - index2 = names[dim - len(degenop) - 1].index(str(gmsm(i))) + index2 = names[dim - len(degenop) - 1].index(str(_gmsm(i))) lKdim_cdr.append(bases[dim - len(degenop) - 1][index2].apply_degeneracies(*degenop)) simplices.append(bases[dim][index1]) faces.append(tuple(lKdim_cdr)) @@ -1335,7 +1336,7 @@ def source_complex(self): sage: differential_morphism.source_complex() # optional - kenzo [K... Chain-Complex] """ - return KenzoChainComplex(sorc_aux(self._kenzo)) + return KenzoChainComplex(_sorc_aux(self._kenzo)) def target_complex(self): r""" @@ -1361,7 +1362,7 @@ def target_complex(self): sage: differential_morphism.target_complex() # optional - kenzo [K... Chain-Complex] """ - return KenzoChainComplex(trgt_aux(self._kenzo)) + return KenzoChainComplex(_trgt_aux(self._kenzo)) def degree(self): r""" @@ -1391,7 +1392,7 @@ def degree(self): sage: kenzo_chcm.null_morphism().degree() # optional - kenzo 0 """ - return degr_aux(self._kenzo).python() + return _degr_aux(self._kenzo).python() def evaluation(self, dim, comb): r""" @@ -1452,9 +1453,9 @@ def evaluation(self, dim, comb): ----------------------------------------------------------------------{CMBN 3} ------------------------------------------------------------------------------ - sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: idx2 = id.sum(id) # optional - kenzo - sage: id.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo + sage: idnt = kenzo_chcm.identity_morphism() # optional - kenzo + sage: idx2 = idnt.sum(idnt) # optional - kenzo + sage: idnt.evaluation(5, [1, 'G5G0', 2, 'G5G2']) # optional - kenzo ----------------------------------------------------------------------{CMBN 5} <1 * G5G0> @@ -1472,7 +1473,7 @@ def evaluation(self, dim, comb): if dim.is_integer(): if isinstance(comb, list): cmbn_list = pairing(comb) - return KenzoObject(evaluation_aux1(self._kenzo, dim, cmbn_list)) + return KenzoObject(_evaluation_aux1(self._kenzo, dim, cmbn_list)) else: raise ValueError("'comb' parameter must be a list") else: @@ -1496,15 +1497,15 @@ def opposite(self): sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo sage: kenzo_chcm # optional - kenzo [K... Chain-Complex] - sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: idnt = kenzo_chcm.identity_morphism() # optional - kenzo + sage: idnt # optional - kenzo [K... Morphism (degree 0): K... -> K...] - sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id = idnt.opposite() # optional - kenzo sage: opps_id # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] - sage: id.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo + sage: idnt.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo ----------------------------------------------------------------------{CMBN 4} <2 * G4G0> @@ -1519,7 +1520,7 @@ def opposite(self): ------------------------------------------------------------------------------ """ - return KenzoChainComplexMorphism(opps(self._kenzo)) + return KenzoChainComplexMorphism(_opps(self._kenzo)) def composite(self, object=None): r""" @@ -1546,25 +1547,25 @@ def composite(self, object=None): sage: s3 = Sphere(3) # optional - kenzo sage: tp22 = s2.tensor_product(s2) # optional - kenzo sage: tp23 = s2.tensor_product(s3) # optional - kenzo - sage: id = tp22.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: idnt = tp22.identity_morphism() # optional - kenzo + sage: idnt # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: null = tp23.null_morphism(target = tp22, degree = 4) # optional - kenzo sage: null # optional - kenzo [K... Morphism (degree 4): K... -> K...] - sage: id.composite((tp22, null)) # optional - kenzo + sage: idnt.composite((tp22, null)) # optional - kenzo [K... Morphism (degree 3): K... -> K...] """ if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(cmps(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(_cmps(self._kenzo, object._kenzo)) elif isinstance(object, KenzoChainComplex): - return KenzoChainComplexMorphism(cmps(self._kenzo, dffr_aux(object._kenzo))) + return KenzoChainComplexMorphism(_cmps(self._kenzo, _dffr_aux(object._kenzo))) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = cmps(rslt, mrph._kenzo) + rslt = _cmps(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def sum(self, object=None): @@ -1592,18 +1593,18 @@ def sum(self, object=None): sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo sage: kenzo_chcm # optional - kenzo [K... Chain-Complex] - sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: idnt = kenzo_chcm.identity_morphism() # optional - kenzo + sage: idnt # optional - kenzo [K... Morphism (degree 0): K... -> K...] - sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id = idnt.opposite() # optional - kenzo sage: opps_id # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: null = kenzo_chcm.null_morphism() # optional - kenzo sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] - sage: idx2 = id.sum(id) # optional - kenzo + sage: idx2 = idnt.sum(idnt) # optional - kenzo sage: idx5 = idx2.sum(\ - ....: (opps_id, id, id, null, idx2.sum(id), opps_id)) # optional - kenzo + ....: (opps_id, idnt, idnt, null, idx2.sum(idnt), opps_id)) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1624,11 +1625,11 @@ def sum(self, object=None): if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(add(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(_add(self._kenzo, object._kenzo)) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = add(rslt, mrph._kenzo) + rslt = _add(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def substract(self, object=None): @@ -1658,18 +1659,18 @@ def substract(self, object=None): sage: kenzo_chcm = KChainComplex(sage_chcm) # optional - kenzo sage: kenzo_chcm # optional - kenzo [K... Chain-Complex] - sage: id = kenzo_chcm.identity_morphism() # optional - kenzo - sage: id # optional - kenzo + sage: idnt = kenzo_chcm.identity_morphism() # optional - kenzo + sage: idnt # optional - kenzo [K... Morphism (degree 0): K... -> K...] - sage: opps_id = id.opposite() # optional - kenzo + sage: opps_id = idnt.opposite() # optional - kenzo sage: opps_id # optional - kenzo [K... Morphism (degree 0): K... -> K...] sage: null = kenzo_chcm.null_morphism() # optional - kenzo sage: null # optional - kenzo [K... Morphism (degree 0): K... -> K...] - sage: idx2 = id.substract(opps_id) # optional - kenzo + sage: idx2 = idnt.substract(opps_id) # optional - kenzo sage: opps_idx2 = idx2.substract\ - ....: ((opps_id, id, id, null, idx2.substract(opps_id))) # optional - kenzo + ....: ((opps_id, idnt, idnt, null, idx2.substract(opps_id))) # optional - kenzo sage: kenzo_chcm.basis(4) # optional - kenzo ['G4G0', 'G4G1'] sage: idx2.evaluation(4, [2, 'G4G0', -5, 'G4G1']) # optional - kenzo @@ -1690,11 +1691,11 @@ def substract(self, object=None): if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(sbtr(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(_sbtr(self._kenzo, object._kenzo)) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = sbtr(rslt, mrph._kenzo) + rslt = _sbtr(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def change_source_target_complex(self, source=None, target=None): @@ -1743,7 +1744,7 @@ def change_source_target_complex(self, source=None, target=None): source = source or self.source_complex() target = target or self.target_complex() return KenzoChainComplexMorphism( - change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + _change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) def destructive_change_source_target_complex(self, source=None, target=None): r""" @@ -1787,7 +1788,7 @@ def destructive_change_source_target_complex(self, source=None, target=None): source = source or self.source_complex() target = target or self.target_complex() return KenzoChainComplexMorphism( - dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + _dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): @@ -1806,9 +1807,9 @@ def build_morphism(source_complex, target_complex, degree, algorithm, strategy, - ``algorithm`` -- A Lisp function defining the mapping (:intr slot in Kenzo) - ``strategy`` -- The strategy (:strt slot in Kenzo), which must be one of - the two strings ``gnrt`` or ``cmbn``, depending if the ``algorithm`` (a Lisp - function) uses as arguments a degree and a generator or a combination, - respectively. + the two strings ``gnrt`` or ``cmbn``, depending if the ``algorithm`` (a Lisp + function) uses as arguments a degree and a generator or a combination, + respectively. - ``orgn`` -- A list containing a description about the origin of the morphism @@ -1833,7 +1834,7 @@ def build_morphism(source_complex, target_complex, degree, algorithm, strategy, """ return KenzoChainComplexMorphism( - build_mrph_aux(source_complex._kenzo, target_complex._kenzo, + _build_mrph_aux(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) @@ -1897,7 +1898,7 @@ def KChainComplexMorphism(morphism): target = KChainComplex(morphism.codomain()) matrix_list = morphism_dictmat(morphism) return KenzoChainComplexMorphism( - kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) + _kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) def s2k_listofmorphisms(l): @@ -1927,7 +1928,7 @@ def s2k_listofmorphisms(l): rslt = EclObject([]) for m in l: rslt = EclObject(KChainComplexMorphism(m)._kenzo).cons(rslt) - return nreverse(rslt) + return _nreverse(rslt) def BicomplexSpectralSequence(l): @@ -1962,4 +1963,4 @@ def BicomplexSpectralSequence(l): [ 0 0] [-4 0] """ - return KenzoSpectralSequence(bicomplex_spectral_sequence(s2k_listofmorphisms(l))) + return KenzoSpectralSequence(_bicomplex_spectral_sequence(s2k_listofmorphisms(l))) From ce108c3832dc6fa91653e1bc7ad44ff0622fe2ed Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 18 Dec 2019 17:00:55 -0800 Subject: [PATCH 296/476] trac 27880: hide some objects from importing. --- src/sage/interfaces/kenzo.py | 250 +++++++++++++++++------------------ 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 05ae36a5176..7c065025ab3 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -61,63 +61,63 @@ # defining the auxiliary functions as wrappers over the kenzo ones -_chcm_mat = EclObject("chcm-mat") -_homologie = EclObject("homologie") -_sphere = EclObject("sphere") -_crts_prdc = EclObject("crts-prdc") -_moore = EclObject("moore") -_k_z = EclObject("k-z") -_k_z2 = EclObject("k-z2") -_k_zp = EclObject("k-zp") -_echcm = EclObject("echcm") -_loop_space = EclObject("loop-space") -_tnsr_prdc = EclObject("tnsr-prdc") -_classifying_space = EclObject("classifying-space") -_suspension = EclObject("suspension") -_homotopy_list = EclObject("homotopy-list") -_nth = EclObject("nth") -_nlig = EclObject("nlig") -_ncol = EclObject("ncol") -_array_dimensions = EclObject("array-dimensions") -_convertmatrice = EclObject("convertmatrice") -_make_array_to_lists = EclObject("make-array-to-lists") -_make_array_from_lists = EclObject("make-array-from-lists") -_chcm_mat2 = EclObject("chcm-mat2") -_build_finite_ss2 = EclObject("build-finite-ss2") -_gmsm = EclObject("gmsm") -_dgop = EclObject("dgop") -_dgop_int_ext = EclObject("dgop-int-ext") -_basis_aux1 = EclObject("basis_aux1") -_orgn_aux1 = EclObject("orgn_aux1") -_dffr_aux1 = EclObject("dffr_aux1") -_kabstractsimplex_aux1 = EclObject("kabstractsimplex_aux1") -_kchaincomplex_aux1 = EclObject("kchaincomplex_aux1") -_sfinitesimplicialset_aux1 = EclObject("sfinitesimplicialset_aux1") -_spectral_sequence_group = EclObject("spectral-sequence-group") -_spectral_sequence_differential_matrix = EclObject("spectral-sequence-differential-matrix") -_eilenberg_moore_spectral_sequence = EclObject("eilenberg-moore-spectral-sequence") -_serre_whitehead_spectral_sequence = EclObject("serre-whitehead-spectral-sequence") -_serre_spectral_sequence_product = EclObject("serre-spectral-sequence-product") -_wedge = EclObject("wedge") -_join = EclObject("join") -_kmorphismchaincomplex_aux1 = EclObject("kmorphismchaincomplex_aux1") -_bicomplex_spectral_sequence = EclObject("bicomplex-spectral-sequence") -_nreverse = EclObject("nreverse") -_smash_product = EclObject("smash-product") -_build_mrph_aux = EclObject("build-mrph-aux") -_zero_mrph = EclObject("zero-mrph") -_idnt_mrph = EclObject("idnt-mrph") -_dffr_aux = EclObject("dffr-aux") -_sorc_aux = EclObject("sorc-aux") -_trgt_aux = EclObject("trgt-aux") -_degr_aux = EclObject("degr-aux") -_evaluation_aux1 = EclObject("evaluation-aux1") -_opps = EclObject("opps") -_cmps = EclObject("cmps") -_add = EclObject("add") -_sbtr = EclObject("sbtr") -_change_sorc_trgt_aux = EclObject("change-sorc-trgt-aux") -_dstr_change_sorc_trgt_aux = EclObject("dstr-change-sorc-trgt-aux") +__chcm_mat__ = EclObject("chcm-mat") +__homologie__ = EclObject("homologie") +__sphere__ = EclObject("sphere") +__crts_prdc__ = EclObject("crts-prdc") +__moore__ = EclObject("moore") +__k_z__ = EclObject("k-z") +__k_z2__ = EclObject("k-z2") +__k_zp__ = EclObject("k-zp") +__echcm__ = EclObject("echcm") +__loop_space__ = EclObject("loop-space") +__tnsr_prdc__ = EclObject("tnsr-prdc") +__classifying_space__ = EclObject("classifying-space") +__suspension__ = EclObject("suspension") +__homotopy_list__ = EclObject("homotopy-list") +__nth__ = EclObject("nth") +__nlig__ = EclObject("nlig") +__ncol__ = EclObject("ncol") +__array_dimensions__ = EclObject("array-dimensions") +__convertmatrice__ = EclObject("convertmatrice") +__make_array_to_lists__ = EclObject("make-array-to-lists") +__make_array_from_lists__ = EclObject("make-array-from-lists") +__chcm_mat2__ = EclObject("chcm-mat2") +__build_finite_ss2__ = EclObject("build-finite-ss2") +__gmsm__ = EclObject("gmsm") +__dgop__ = EclObject("dgop") +__dgop_int_ext__ = EclObject("dgop-int-ext") +__basis_aux1__ = EclObject("basis_aux1") +__orgn_aux1__ = EclObject("orgn_aux1") +__dffr_aux_1__ = EclObject("dffr_aux1") +__kabstractsimplex_aux1__ = EclObject("kabstractsimplex_aux1") +__kchaincomplex_aux1__ = EclObject("kchaincomplex_aux1") +__sfinitesimplicialset_aux1__ = EclObject("sfinitesimplicialset_aux1") +__spectral_sequence_group__ = EclObject("spectral-sequence-group") +__spectral_sequence_differential_matrix__ = EclObject("spectral-sequence-differential-matrix") +__eilenberg_moore_spectral_sequence__ = EclObject("eilenberg-moore-spectral-sequence") +__serre_whitehead_spectral_sequence__ = EclObject("serre-whitehead-spectral-sequence") +__serre_spectral_sequence_product__ = EclObject("serre-spectral-sequence-product") +__wedge__ = EclObject("wedge") +__join__ = EclObject("join") +__kmorphismchaincomplex_aux1__ = EclObject("kmorphismchaincomplex_aux1") +__bicomplex_spectral_sequence__ = EclObject("bicomplex-spectral-sequence") +__nreverse__ = EclObject("nreverse") +__smash_product__ = EclObject("smash-product") +__build_mrph_aux__ = EclObject("build-mrph-aux") +__zero_mrph__ = EclObject("zero-mrph") +__idnt_mrph__ = EclObject("idnt-mrph") +__dffr_aux__ = EclObject("dffr-aux") +__sorc_aux__ = EclObject("sorc-aux") +__trgt_aux__ = EclObject("trgt-aux") +__degr_aux__ = EclObject("degr-aux") +__evaluation_aux1__ = EclObject("evaluation-aux1") +__opps__ = EclObject("opps") +__cmps__ = EclObject("cmps") +__add__ = EclObject("add") +__sbtr__ = EclObject("sbtr") +__change_sorc_trgt_aux__ = EclObject("change-sorc-trgt-aux") +__dstr_change_sorc_trgt_aux__ = EclObject("dstr-change-sorc-trgt-aux") def Sphere(n): @@ -141,7 +141,7 @@ def Sphere(n): sage: [s2.homology(i) for i in range(8)] # optional - kenzo [Z, 0, Z, 0, 0, 0, 0, 0] """ - kenzosphere = _sphere(n) + kenzosphere = __sphere__(n) return KenzoSimplicialSet(kenzosphere) @@ -172,7 +172,7 @@ def MooreSpace(m, n): sage: [m24.homology(i) for i in range(8)] # optional - kenzo [Z, 0, 0, 0, C2, 0, 0, 0] """ - kenzomoore = _moore(m, n) + kenzomoore = __moore__(m, n) return KenzoSimplicialSet(kenzomoore) @@ -205,13 +205,13 @@ def EilenbergMacLaneSpace(G, n): [Z, 0, 0, C2, 0, C2, C2, C2] """ if G == ZZ: - kenzospace = _k_z(n) + kenzospace = __k_z__(n) return KenzoSimplicialGroup(kenzospace) elif G == AdditiveAbelianGroup([2]): - kenzospace = _k_z2(n) + kenzospace = __k_z2__(n) return KenzoSimplicialGroup(kenzospace) elif G in CommutativeAdditiveGroups() and G.is_cyclic(): - kenzospace = _k_zp(G.cardinality(), n) + kenzospace = __k_zp__(G.cardinality(), n) return KenzoSimplicialGroup(kenzospace) else: raise NotImplementedError("Eilenberg-MacLane spaces are only supported over ZZ and ZZ_n") @@ -234,8 +234,8 @@ def __init__(self, kenzo_object): TESTS:: sage: from sage.interfaces.kenzo import KenzoObject # optional -kenzo - sage: from sage.interfaces.kenzo import _sphere # optional -kenzo - sage: ks = _sphere(2) # optional -kenzo + sage: from sage.interfaces.kenzo import __sphere__ # optional -kenzo + sage: ks = __sphere__(2) # optional -kenzo sage: ks # optional -kenzo sage: s2 = KenzoObject(ks) # optional -kenzo @@ -291,7 +291,7 @@ def group(self, p, i, j): sage: EMS.group(0, -1, 3) # optional - kenzo Trivial group """ - invs = _spectral_sequence_group(self._kenzo, p, i, j).python() + invs = __spectral_sequence_group__(self._kenzo, p, i, j).python() if not invs: invs = [] return AdditiveAbelianGroup(invs) @@ -325,7 +325,7 @@ def matrix(self, p, i, j): [ 3 0 -3] [ 0 2 -3] """ - klist = _spectral_sequence_differential_matrix(self._kenzo, p, i, j) + klist = __spectral_sequence_differential_matrix__(self._kenzo, p, i, j) plist = klist.python() if plist is None or plist == [None]: i = len(self.group(p, i, j).invariants()) @@ -434,10 +434,10 @@ def homology(self, n): sage: s2.homology(2) # optional - kenzo Z """ - echcm1 = _echcm(self._kenzo) - m1 = _chcm_mat(echcm1, n) - m2 = _chcm_mat(echcm1, n + 1) - homology = _homologie(m1, m2) + echcm1 = __echcm__(self._kenzo) + m1 = __chcm_mat__(echcm1, n) + m2 = __chcm_mat__(echcm1, n + 1) + homology = __homologie__(m1, m2) lhomomology = [i for i in EclListIterator(homology)] res = [] for component in lhomomology: @@ -468,7 +468,7 @@ def tensor_product(self, other): sage: [p.homology(i) for i in range(8)] # optional - kenzo [Z, 0, Z, Z, 0, Z, 0, 0] """ - return KenzoChainComplex(_tnsr_prdc(self._kenzo, other._kenzo)) + return KenzoChainComplex(__tnsr_prdc__(self._kenzo, other._kenzo)) def basis(self, dim): r""" @@ -502,7 +502,7 @@ def basis(self, dim): Basis in dimension 5: ['G5G0', 'G5G1', 'G5G2'] """ - return _basis_aux1(self._kenzo, dim).python() + return __basis_aux1__(self._kenzo, dim).python() def identity_morphism(self): r""" @@ -521,7 +521,7 @@ def identity_morphism(self): sage: type(idnt) # optional - kenzo """ - return KenzoChainComplexMorphism(_idnt_mrph(self._kenzo)) + return KenzoChainComplexMorphism(__idnt_mrph__(self._kenzo)) def null_morphism(self, target=None, degree=None): r""" @@ -567,7 +567,7 @@ def null_morphism(self, target=None, degree=None): elif (not degree == 0) and (not degree.is_integer()): raise ValueError("'degree' parameter must be an Integer number") else: - return KenzoChainComplexMorphism(_zero_mrph(self._kenzo, target._kenzo, degree)) + return KenzoChainComplexMorphism(__zero_mrph__(self._kenzo, target._kenzo, degree)) def differential(self, dim=None, comb=None): r""" @@ -624,9 +624,9 @@ def differential(self, dim=None, comb=None): """ if dim is not None and comb is not None: cmbn_list = pairing(comb) - return KenzoObject(_dffr_aux1(self._kenzo, dim, cmbn_list)) + return KenzoObject(__dffr_aux_1__(self._kenzo, dim, cmbn_list)) else: - return KenzoChainComplexMorphism(_dffr_aux(self._kenzo)) + return KenzoChainComplexMorphism(__dffr_aux__(self._kenzo)) def orgn(self): r""" @@ -643,7 +643,7 @@ def orgn(self): sage: A.orgn() # optional - kenzo '(CRTS-PRDC [K... Simplicial-Group] [K... Simplicial-Set])' """ - return str(_orgn_aux1(self._kenzo)) + return str(__orgn_aux1__(self._kenzo)) class KenzoSimplicialSet(KenzoChainComplex): @@ -675,7 +675,7 @@ def loop_space(self, n=1): sage: [l2.homology(i) for i in range(8)] # optional - kenzo [Z, Z, Z, Z, Z, Z, Z, Z] """ - return KenzoSimplicialGroup(_loop_space(self._kenzo, n)) + return KenzoSimplicialGroup(__loop_space__(self._kenzo, n)) def cartesian_product(self, other): r""" @@ -700,7 +700,7 @@ def cartesian_product(self, other): sage: [p.homology(i) for i in range(6)] # optional - kenzo [Z, 0, Z, Z, 0, Z] """ - prod_kenzo = _crts_prdc(self._kenzo, other._kenzo) + prod_kenzo = __crts_prdc__(self._kenzo, other._kenzo) return KenzoSimplicialSet(prod_kenzo) def suspension(self): @@ -721,7 +721,7 @@ def suspension(self): sage: [s.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, Z, 0] """ - return KenzoSimplicialSet(_suspension(self._kenzo)) + return KenzoSimplicialSet(__suspension__(self._kenzo)) def homotopy_group(self, n): """ @@ -742,7 +742,7 @@ def homotopy_group(self, n): if n not in ZZ or n < 2: raise ValueError("""homotopy groups can only be computed for dimensions greater than 1""") - lgens = _homotopy_list(self._kenzo, n).python() + lgens = __homotopy_list__(self._kenzo, n).python() if lgens is not None: trgens = [0 if i == 1 else i for i in sorted(lgens)] return AbelianGroup(trgens) @@ -772,7 +772,7 @@ def em_spectral_sequence(self): if self.homology(1).invariants(): raise ValueError("""Eilenberg-Moore spectral sequence implemented only for 1-reduced simplicial sets""") - return KenzoSpectralSequence(_eilenberg_moore_spectral_sequence(self._kenzo)) + return KenzoSpectralSequence(__eilenberg_moore_spectral_sequence__(self._kenzo)) def sw_spectral_sequence(self): r""" @@ -795,7 +795,7 @@ def sw_spectral_sequence(self): 0 0 0 0 0 Z 0 0 Z 0 """ - return KenzoSpectralSequence(_serre_whitehead_spectral_sequence(self._kenzo)) + return KenzoSpectralSequence(__serre_whitehead_spectral_sequence__(self._kenzo)) def serre_spectral_sequence(self): r""" @@ -820,7 +820,7 @@ def serre_spectral_sequence(self): 0 0 0 Z 0 Z """ - return KenzoSpectralSequence(_serre_spectral_sequence_product(self._kenzo)) + return KenzoSpectralSequence(__serre_spectral_sequence_product__(self._kenzo)) def wedge(self, other): r""" @@ -845,7 +845,7 @@ def wedge(self, other): sage: [w.homology(i) for i in range(6)] # optional - kenzo [Z, 0, Z, Z, 0, 0] """ - wedge_kenzo = _wedge(self._kenzo, other._kenzo) + wedge_kenzo = __wedge__(self._kenzo, other._kenzo) return KenzoSimplicialSet(wedge_kenzo) def join(self, other): @@ -871,7 +871,7 @@ def join(self, other): sage: [j.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, 0, 0] """ - join_kenzo = _join(self._kenzo, other._kenzo) + join_kenzo = __join__(self._kenzo, other._kenzo) return KenzoSimplicialSet(join_kenzo) def smash_product(self, other): @@ -897,7 +897,7 @@ def smash_product(self, other): sage: [s.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, 0, Z] """ - smash_kenzo = _smash_product(self._kenzo, other._kenzo) + smash_kenzo = __smash_product__(self._kenzo, other._kenzo) return KenzoSimplicialSet(smash_kenzo) @@ -925,7 +925,7 @@ def classifying_space(self): sage: [c.homology(i) for i in range(8)] # optional - kenzo [Z, 0, 0, 0, C2, 0, 0, 0] """ - return KenzoSimplicialGroup(_classifying_space(self._kenzo)) + return KenzoSimplicialGroup(__classifying_space__(self._kenzo)) def k2s_matrix(kmatrix): @@ -946,8 +946,8 @@ def k2s_matrix(kmatrix): [3 2 1] [1 1 1] """ - dimensions = _array_dimensions(kmatrix).python() - kmatrix_list = _make_array_to_lists(kmatrix).python() + dimensions = __array_dimensions__(kmatrix).python() + kmatrix_list = __make_array_to_lists__(kmatrix).python() return matrix(dimensions[0], dimensions[1], kmatrix_list) @@ -974,7 +974,7 @@ def s2k_matrix(smatrix): dimensions = smatrix.dimensions() for i in smatrix.rows(): initcontents.append(i.list()) - return _make_array_from_lists(dimensions[0], dimensions[1], initcontents) + return __make_array_from_lists__(dimensions[0], dimensions[1], initcontents) def s2k_dictmat(sdictmat): @@ -1060,7 +1060,7 @@ def KChainComplex(chain_complex): d = chain_complex.differential() chcm = s2k_dictmat(d) str_orgn = str(d)[1:-1].replace(":", " ").replace(" ", ".").replace("\n", "").replace(",", "") - return KenzoChainComplex(_kchaincomplex_aux1(chcm, str_orgn)) + return KenzoChainComplex(__kchaincomplex_aux1__(chcm, str_orgn)) def SChainComplex(kchaincomplex, start=0, end=15): @@ -1092,9 +1092,9 @@ def SChainComplex(kchaincomplex, start=0, end=15): """ matrices = {} for i in range(start, end): - dffr_i = _chcm_mat2(kchaincomplex._kenzo, i) - if ((_nlig(dffr_i).python() != 0) and (_ncol(dffr_i).python() != 0)): - matrices[i] = k2s_matrix(_convertmatrice(dffr_i)) + dffr_i = __chcm_mat2__(kchaincomplex._kenzo, i) + if ((__nlig__(dffr_i).python() != 0) and (__ncol__(dffr_i).python() != 0)): + matrices[i] = k2s_matrix(__convertmatrice__(dffr_i)) return ChainComplex(matrices, degree=-1) @@ -1127,12 +1127,12 @@ def SAbstractSimplex(simplex, dim): sage: SAbSm2.dimension() # optional - kenzo 11 """ - degeneracies = _dgop_int_ext(_dgop(simplex._kenzo)).python() + degeneracies = __dgop_int_ext__(__dgop__(simplex._kenzo)).python() if degeneracies is None: degeneracies = [] else: degeneracies = tuple(degeneracies) - name = _gmsm(simplex._kenzo).python() + name = __gmsm__(simplex._kenzo).python() return AbstractSimplex(dim, degeneracies, name=name) @@ -1161,7 +1161,7 @@ def KAbstractSimplex(simplex): sage: SAbSm.dimension() == SAbSm2.dimension() # optional - kenzo True """ - return KenzoObject(_kabstractsimplex_aux1(simplex.degeneracies(), + return KenzoObject(__kabstractsimplex_aux1__(simplex.degeneracies(), 's' + str(hash(simplex)))) @@ -1227,7 +1227,7 @@ def KFiniteSimplicialSet(sset): degen_z.append(name) auxiliar_list.append(degen_z) list_rslt.append(auxiliar_list) - return KenzoSimplicialSet(_build_finite_ss2(list_rslt)) + return KenzoSimplicialSet(__build_finite_ss2__(list_rslt)) def SFiniteSimplicialSet(ksimpset, limit): @@ -1270,23 +1270,23 @@ def SFiniteSimplicialSet(ksimpset, limit): sage: SS1vS3.homology() # optional - kenzo {0: 0, 1: Z, 2: 0, 3: Z} """ - list_orgn = _orgn_aux1(ksimpset._kenzo).python() - if _nth(0, list_orgn).python()[0] == 'CRTS-PRDC': + list_orgn = __orgn_aux1__(ksimpset._kenzo).python() + if __nth__(0, list_orgn).python()[0] == 'CRTS-PRDC': return SFiniteSimplicialSet( - KenzoSimplicialSet(_nth(1, list_orgn)), limit).cartesian_product( - SFiniteSimplicialSet(KenzoSimplicialSet(_nth(2, list_orgn)), limit)) + KenzoSimplicialSet(__nth__(1, list_orgn)), limit).cartesian_product( + SFiniteSimplicialSet(KenzoSimplicialSet(__nth__(2, list_orgn)), limit)) rslt = {} simplices = [] faces = [] bases = [] names = [] for k in range(limit + 1): - basis_k = _basis_aux1(ksimpset._kenzo, k) + basis_k = __basis_aux1__(ksimpset._kenzo, k) names_k = ksimpset.basis(k) lbasis_k = [AbstractSimplex(k, name=i) for i in EclListIterator(basis_k)] bases.append(lbasis_k) names.append(names_k) - all_simplices = _sfinitesimplicialset_aux1(ksimpset._kenzo, limit) + all_simplices = __sfinitesimplicialset_aux1__(ksimpset._kenzo, limit) lall_simplices = [i for i in EclListIterator(all_simplices)] dim = 1 for Kdim in lall_simplices: @@ -1294,10 +1294,10 @@ def SFiniteSimplicialSet(ksimpset, limit): index1 = names[dim].index(str(simp.car())) lKdim_cdr = [] for i in EclListIterator(simp.cdr()): - degenop = _dgop_int_ext(_dgop(i)).python() + degenop = __dgop_int_ext__(__dgop__(i)).python() if degenop is None: degenop = [] - index2 = names[dim - len(degenop) - 1].index(str(_gmsm(i))) + index2 = names[dim - len(degenop) - 1].index(str(__gmsm__(i))) lKdim_cdr.append(bases[dim - len(degenop) - 1][index2].apply_degeneracies(*degenop)) simplices.append(bases[dim][index1]) faces.append(tuple(lKdim_cdr)) @@ -1336,7 +1336,7 @@ def source_complex(self): sage: differential_morphism.source_complex() # optional - kenzo [K... Chain-Complex] """ - return KenzoChainComplex(_sorc_aux(self._kenzo)) + return KenzoChainComplex(__sorc_aux__(self._kenzo)) def target_complex(self): r""" @@ -1362,7 +1362,7 @@ def target_complex(self): sage: differential_morphism.target_complex() # optional - kenzo [K... Chain-Complex] """ - return KenzoChainComplex(_trgt_aux(self._kenzo)) + return KenzoChainComplex(__trgt_aux__(self._kenzo)) def degree(self): r""" @@ -1392,7 +1392,7 @@ def degree(self): sage: kenzo_chcm.null_morphism().degree() # optional - kenzo 0 """ - return _degr_aux(self._kenzo).python() + return __degr_aux__(self._kenzo).python() def evaluation(self, dim, comb): r""" @@ -1473,7 +1473,7 @@ def evaluation(self, dim, comb): if dim.is_integer(): if isinstance(comb, list): cmbn_list = pairing(comb) - return KenzoObject(_evaluation_aux1(self._kenzo, dim, cmbn_list)) + return KenzoObject(__evaluation_aux1__(self._kenzo, dim, cmbn_list)) else: raise ValueError("'comb' parameter must be a list") else: @@ -1520,7 +1520,7 @@ def opposite(self): ------------------------------------------------------------------------------ """ - return KenzoChainComplexMorphism(_opps(self._kenzo)) + return KenzoChainComplexMorphism(__opps__(self._kenzo)) def composite(self, object=None): r""" @@ -1559,13 +1559,13 @@ def composite(self, object=None): if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(_cmps(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(__cmps__(self._kenzo, object._kenzo)) elif isinstance(object, KenzoChainComplex): - return KenzoChainComplexMorphism(_cmps(self._kenzo, _dffr_aux(object._kenzo))) + return KenzoChainComplexMorphism(__cmps__(self._kenzo, __dffr_aux__(object._kenzo))) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = _cmps(rslt, mrph._kenzo) + rslt = __cmps__(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def sum(self, object=None): @@ -1625,11 +1625,11 @@ def sum(self, object=None): if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(_add(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(__add__(self._kenzo, object._kenzo)) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = _add(rslt, mrph._kenzo) + rslt = __add__(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def substract(self, object=None): @@ -1691,11 +1691,11 @@ def substract(self, object=None): if object is None: return self if isinstance(object, KenzoChainComplexMorphism): - return KenzoChainComplexMorphism(_sbtr(self._kenzo, object._kenzo)) + return KenzoChainComplexMorphism(__sbtr__(self._kenzo, object._kenzo)) elif isinstance(object, tuple): rslt = self._kenzo for mrph in object: - rslt = _sbtr(rslt, mrph._kenzo) + rslt = __sbtr__(rslt, mrph._kenzo) return KenzoChainComplexMorphism(rslt) def change_source_target_complex(self, source=None, target=None): @@ -1744,7 +1744,7 @@ def change_source_target_complex(self, source=None, target=None): source = source or self.source_complex() target = target or self.target_complex() return KenzoChainComplexMorphism( - _change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + __change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) def destructive_change_source_target_complex(self, source=None, target=None): r""" @@ -1788,7 +1788,7 @@ def destructive_change_source_target_complex(self, source=None, target=None): source = source or self.source_complex() target = target or self.target_complex() return KenzoChainComplexMorphism( - _dstr_change_sorc_trgt_aux(self._kenzo, source._kenzo, target._kenzo)) + __dstr_change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): @@ -1834,7 +1834,7 @@ def build_morphism(source_complex, target_complex, degree, algorithm, strategy, """ return KenzoChainComplexMorphism( - _build_mrph_aux(source_complex._kenzo, target_complex._kenzo, + __build_mrph_aux__(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":"+strategy, orgn)) @@ -1898,7 +1898,7 @@ def KChainComplexMorphism(morphism): target = KChainComplex(morphism.codomain()) matrix_list = morphism_dictmat(morphism) return KenzoChainComplexMorphism( - _kmorphismchaincomplex_aux1(matrix_list, source._kenzo, target._kenzo)) + __kmorphismchaincomplex_aux1__(matrix_list, source._kenzo, target._kenzo)) def s2k_listofmorphisms(l): @@ -1928,7 +1928,7 @@ def s2k_listofmorphisms(l): rslt = EclObject([]) for m in l: rslt = EclObject(KChainComplexMorphism(m)._kenzo).cons(rslt) - return _nreverse(rslt) + return __nreverse__(rslt) def BicomplexSpectralSequence(l): @@ -1963,4 +1963,4 @@ def BicomplexSpectralSequence(l): [ 0 0] [-4 0] """ - return KenzoSpectralSequence(_bicomplex_spectral_sequence(s2k_listofmorphisms(l))) + return KenzoSpectralSequence(__bicomplex_spectral_sequence__(s2k_listofmorphisms(l))) From 87718ea01cdb21c5152db43db2b17be846eb7719 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 19 Dec 2019 13:48:24 +0100 Subject: [PATCH 297/476] Treat case with trivial modules in SChainComplex --- src/sage/interfaces/kenzo.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 7c065025ab3..997357a3b1c 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -1089,12 +1089,28 @@ def SChainComplex(kchaincomplex, start=0, end=15): sage: sage_chcm = ChainComplex({1: m1, 4: m4, 5: m5}, degree = -1) # optional - kenzo sage: SChainComplex(KChainComplex(sage_chcm)) == sage_chcm # optional - kenzo True + + :: + + sage: from sage.interfaces.kenzo import SChainComplex, Sphere + sage: S4 = Sphere(4) + sage: C = SChainComplex(S4) + sage: C + Chain complex with at most 3 nonzero terms over Integer Ring + sage: C._ascii_art_() + 0 <-- C_4 <-- 0 ... 0 <-- C_0 <-- 0 + sage: [C.homology(i) for i in range(6)] + [Z, 0, 0, 0, Z, 0] """ matrices = {} for i in range(start, end): dffr_i = __chcm_mat2__(kchaincomplex._kenzo, i) - if ((__nlig__(dffr_i).python() != 0) and (__ncol__(dffr_i).python() != 0)): + nlig = __nlig__(dffr_i).python() + ncol = __ncol__(dffr_i).python() + if ((nlig != 0) and (ncol != 0)): matrices[i] = k2s_matrix(__convertmatrice__(dffr_i)) + else: + matrices[i] = matrix(nlig, ncol) return ChainComplex(matrices, degree=-1) From 96c9050131672175f6b065218c743c48dc629940 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 15 Jan 2020 15:31:34 +0100 Subject: [PATCH 298/476] Document that kenzo simplicial set inherits from kenzo chain complex --- src/sage/interfaces/kenzo.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 997357a3b1c..ab4dc17cd74 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -411,11 +411,13 @@ def table(self, p, i1, i2, j1, j2): class KenzoChainComplex(KenzoObject): r""" - Wrapper to Kenzo chain complexes. + Wrapper to Kenzo chain complexes. Kenzo simplicial sets are a particular case + of Kenzo chain complexes. """ def homology(self, n): r""" - Return the ``n``'th homology group of the kenzo chain complex + Return the ``n``'th homology group of the chain complex associated to this + kenzo object. INPUT: @@ -472,7 +474,8 @@ def tensor_product(self, other): def basis(self, dim): r""" - Return the list of generators of the Kenzo chain complex ``self`` in dimension ``dim``. + Return the list of generators of the chain complex associated to the kenzo + object ``self`` in dimension ``dim``. INPUT: @@ -649,6 +652,9 @@ def orgn(self): class KenzoSimplicialSet(KenzoChainComplex): r""" Wrapper to Kenzo simplicial sets. + + In Kenzo, the homology of a simplicial set in computed from its associated + chain complex. Hence, this class inherits from `KenzoChainComplex`. """ def loop_space(self, n=1): From 6a6678b1f8828e6e04281faabf850182b1d1fc99 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 21 May 2020 16:48:58 +0200 Subject: [PATCH 299/476] Added warnings for simply-connectedness --- src/sage/interfaces/kenzo.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index ab4dc17cd74..dd3aeae9fee 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -744,6 +744,12 @@ def homotopy_group(self, n): sage: p = s2.cartesian_product(s2) # optional - kenzo sage: p.homotopy_group(3) # optional - kenzo Multiplicative Abelian group isomorphic to Z x Z + + + .. WARNING:: + + This method assumes that the underlying space is simply connected. + You might get wrong answers if it is not. """ if n not in ZZ or n < 2: raise ValueError("""homotopy groups can only be computed @@ -774,6 +780,12 @@ def em_spectral_sequence(self): 0 0 Z 0 0 0 0 0 0 0 0 0 0 0 0 + + + .. WARNING:: + + This method assumes that the underlying space is simply connected. + You might get wrong answers if it is not. """ if self.homology(1).invariants(): raise ValueError("""Eilenberg-Moore spectral sequence implemented @@ -790,7 +802,7 @@ def sw_spectral_sequence(self): EXAMPLES:: - sage: from sage.interfaces.kenzo import Sphere + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo sage: S3 = Sphere(3) # optional - kenzo sage: E = S3.sw_spectral_sequence() # optional - kenzo sage: T = E.table(0, 0, 4, 0, 4) # optional - kenzo @@ -801,6 +813,9 @@ def sw_spectral_sequence(self): 0 0 0 0 0 Z 0 0 Z 0 """ + if self.homology(1).invariants(): + raise ValueError("""Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""") return KenzoSpectralSequence(__serre_whitehead_spectral_sequence__(self._kenzo)) def serre_spectral_sequence(self): @@ -825,7 +840,15 @@ def serre_spectral_sequence(self): 0 0 0 0 0 0 Z 0 Z + + .. WARNING:: + + This method assumes that the underlying space is simply connected. + You might get wrong answers if it is not. """ + if self.homology(1).invariants(): + raise ValueError("""Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""") return KenzoSpectralSequence(__serre_spectral_sequence_product__(self._kenzo)) def wedge(self, other): From 4b04baa2d701d876d2361dda1484db05fadf3e87 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Thu, 21 May 2020 17:01:45 +0200 Subject: [PATCH 300/476] Kenzo version bump --- build/pkgs/kenzo/checksums.ini | 6 +++--- build/pkgs/kenzo/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/kenzo/checksums.ini b/build/pkgs/kenzo/checksums.ini index f4068e4588d..ab13adc9f9c 100644 --- a/build/pkgs/kenzo/checksums.ini +++ b/build/pkgs/kenzo/checksums.ini @@ -1,4 +1,4 @@ tarball=kenzo-1.1.8.tar.gz -sha1=365185b1c3373060bd7124937aad13c3df82b4b7 -md5=7cd942e5c725327624266a4cf094113c -cksum=2540973636 +sha1=f153b0c172b6c11851a5f248947b61b0bf5be527 +md5=98adc197c6f23716a6ddd115115ab4f6 +cksum=880933361 diff --git a/build/pkgs/kenzo/package-version.txt b/build/pkgs/kenzo/package-version.txt index 18efdb9ae67..512a1faa680 100644 --- a/build/pkgs/kenzo/package-version.txt +++ b/build/pkgs/kenzo/package-version.txt @@ -1 +1 @@ -1.1.8 +1.1.9 From 9c021a7e98cd76723a6826adb8cc0adb0f88e78a Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Fri, 22 May 2020 00:39:36 +0200 Subject: [PATCH 301/476] Fixed checksums.ini --- build/pkgs/kenzo/checksums.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/kenzo/checksums.ini b/build/pkgs/kenzo/checksums.ini index ab13adc9f9c..22ef2a25127 100644 --- a/build/pkgs/kenzo/checksums.ini +++ b/build/pkgs/kenzo/checksums.ini @@ -1,4 +1,5 @@ -tarball=kenzo-1.1.8.tar.gz +tarball=kenzo-1.1.9.tar.gz +upstream_url=https://github.com/miguelmarco/kenzo/releases/download/1.1.9/kenzo-1.1.9.tar.gz sha1=f153b0c172b6c11851a5f248947b61b0bf5be527 md5=98adc197c6f23716a6ddd115115ab4f6 cksum=880933361 From 217e47c23a094e28573a615bd42fc29232d38f3c Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 27 May 2020 18:36:40 -0700 Subject: [PATCH 302/476] trac 27880: various fixes: - tag some more doctests as "optional - kenzo" - change Kenzo's spkg-install.in to use sdh_install instead of mv - change initialization of names in sage.interfaces.kenzo: don't raise an error if Kenzo is not installed, and clean up how the names are defined. --- build/pkgs/kenzo/spkg-install.in | 2 +- src/sage/interfaces/kenzo.py | 177 +++++++++++++++++-------------- 2 files changed, 99 insertions(+), 80 deletions(-) diff --git a/build/pkgs/kenzo/spkg-install.in b/build/pkgs/kenzo/spkg-install.in index cd64e0213c4..294a543d7e7 100644 --- a/build/pkgs/kenzo/spkg-install.in +++ b/build/pkgs/kenzo/spkg-install.in @@ -8,7 +8,7 @@ cd src ecl < compile.lisp echo "moving kenzo--all-systems.fasb to $SAGE_LOCAL/lib/ecl/kenzo.fas" -mv kenzo--all-systems.fasb $SAGE_LOCAL/lib/ecl/kenzo.fas +sdh_install -T kenzo--all-systems.fasb $SAGE_LOCAL/lib/ecl/kenzo.fas if [ $? -ne 0 ]; then diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index dd3aeae9fee..58222b49a7e 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -39,85 +39,104 @@ from sage.homology.simplicial_set import AbstractSimplex, SimplicialSet from sage.libs.ecl import EclObject, ecl_eval, EclListIterator -from sage.misc.package import installed_packages, PackageNotFoundError -if not 'kenzo' in installed_packages(): - raise PackageNotFoundError('kenzo') +def kenzo_installed(): + """ + True if Kenzo is installed. + + EXAMPLES:: -# Redirection of ECL and Maxima stdout to /dev/null -# This is also done in the Maxima library, but we -# also do it here for redundancy. -ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream - (make-concatenated-stream) (make-broadcast-stream)))""") -ecl_eval("(setf original-standard-output *standard-output*)") -ecl_eval("(setf *standard-output* *dev-null*)") + sage: from sage.interfaces.kenzo import kenzo_installed + sage: kenzo_installed() # random + False + """ + # Redirection of ECL and Maxima stdout to /dev/null + # This is also done in the Maxima library, but we + # also do it here for redundancy. + ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream + (make-concatenated-stream) (make-broadcast-stream)))""") + ecl_eval("(setf original-standard-output *standard-output*)") + ecl_eval("(setf *standard-output* *dev-null*)") -# Loading and initialization of Kenzo -# Note that it will load kenzo.fas file from $SAGE_LOCAL/lib/ecl/ -ecl_eval("(require :kenzo)") -ecl_eval("(in-package :cat)") -ecl_eval("(setf *HOMOLOGY-VERBOSE* nil)") + try: + ecl_eval("(require :kenzo)") + except RuntimeError: + return False + return True # defining the auxiliary functions as wrappers over the kenzo ones -__chcm_mat__ = EclObject("chcm-mat") -__homologie__ = EclObject("homologie") -__sphere__ = EclObject("sphere") -__crts_prdc__ = EclObject("crts-prdc") -__moore__ = EclObject("moore") -__k_z__ = EclObject("k-z") -__k_z2__ = EclObject("k-z2") -__k_zp__ = EclObject("k-zp") -__echcm__ = EclObject("echcm") -__loop_space__ = EclObject("loop-space") -__tnsr_prdc__ = EclObject("tnsr-prdc") -__classifying_space__ = EclObject("classifying-space") -__suspension__ = EclObject("suspension") -__homotopy_list__ = EclObject("homotopy-list") -__nth__ = EclObject("nth") -__nlig__ = EclObject("nlig") -__ncol__ = EclObject("ncol") -__array_dimensions__ = EclObject("array-dimensions") -__convertmatrice__ = EclObject("convertmatrice") -__make_array_to_lists__ = EclObject("make-array-to-lists") -__make_array_from_lists__ = EclObject("make-array-from-lists") -__chcm_mat2__ = EclObject("chcm-mat2") -__build_finite_ss2__ = EclObject("build-finite-ss2") -__gmsm__ = EclObject("gmsm") -__dgop__ = EclObject("dgop") -__dgop_int_ext__ = EclObject("dgop-int-ext") -__basis_aux1__ = EclObject("basis_aux1") -__orgn_aux1__ = EclObject("orgn_aux1") -__dffr_aux_1__ = EclObject("dffr_aux1") -__kabstractsimplex_aux1__ = EclObject("kabstractsimplex_aux1") -__kchaincomplex_aux1__ = EclObject("kchaincomplex_aux1") -__sfinitesimplicialset_aux1__ = EclObject("sfinitesimplicialset_aux1") -__spectral_sequence_group__ = EclObject("spectral-sequence-group") -__spectral_sequence_differential_matrix__ = EclObject("spectral-sequence-differential-matrix") -__eilenberg_moore_spectral_sequence__ = EclObject("eilenberg-moore-spectral-sequence") -__serre_whitehead_spectral_sequence__ = EclObject("serre-whitehead-spectral-sequence") -__serre_spectral_sequence_product__ = EclObject("serre-spectral-sequence-product") -__wedge__ = EclObject("wedge") -__join__ = EclObject("join") -__kmorphismchaincomplex_aux1__ = EclObject("kmorphismchaincomplex_aux1") -__bicomplex_spectral_sequence__ = EclObject("bicomplex-spectral-sequence") -__nreverse__ = EclObject("nreverse") -__smash_product__ = EclObject("smash-product") -__build_mrph_aux__ = EclObject("build-mrph-aux") -__zero_mrph__ = EclObject("zero-mrph") -__idnt_mrph__ = EclObject("idnt-mrph") -__dffr_aux__ = EclObject("dffr-aux") -__sorc_aux__ = EclObject("sorc-aux") -__trgt_aux__ = EclObject("trgt-aux") -__degr_aux__ = EclObject("degr-aux") -__evaluation_aux1__ = EclObject("evaluation-aux1") -__opps__ = EclObject("opps") -__cmps__ = EclObject("cmps") -__add__ = EclObject("add") -__sbtr__ = EclObject("sbtr") -__change_sorc_trgt_aux__ = EclObject("change-sorc-trgt-aux") -__dstr_change_sorc_trgt_aux__ = EclObject("dstr-change-sorc-trgt-aux") +kenzo_names = ['add', + 'array-dimensions', + 'basis_aux1', + 'basis_aux1', + 'bicomplex-spectral-sequence', + 'build-finite-ss2', + 'build-mrph-aux', + 'change-sorc-trgt-aux', + 'chcm-mat', + 'chcm-mat2', + 'classifying-space', + 'cmps', + 'convertmatrice', + 'crts-prdc', + 'degr-aux', + 'dffr-aux', + 'dffr_aux1', + 'dgop', + 'dgop-int-ext', + 'dstr-change-sorc-trgt-aux', + 'echcm', + 'eilenberg-moore-spectral-sequence', + 'evaluation-aux1', + 'gmsm', + 'homologie', + 'homotopy-list', + 'idnt-mrph', + 'join', + 'k-z', + 'k-z2', + 'k-zp', + 'kabstractsimplex_aux1', + 'kchaincomplex_aux1', + 'kmorphismchaincomplex_aux1', + 'loop-space', + 'make-array-from-lists', + 'make-array-to-lists', + 'moore', + 'ncol', + 'nlig', + 'nreverse', + 'nth', + 'opps', + 'orgn_aux1', + 'sbtr', + 'serre-spectral-sequence-product', + 'serre-whitehead-spectral-sequence', + 'sfinitesimplicialset_aux1', + 'smash-product', + 'sorc-aux', + 'spectral-sequence-differential-matrix', + 'spectral-sequence-group', + 'sphere', + 'suspension', + 'tnsr-prdc', + 'trgt-aux', + 'wedge', + 'zero-mrph'] + + +# Now initialize Kenzo. For each string s in kenzo_names, the +# following defines __s__, a wrapper for a Kenzo function. For +# example __sphere__ is defined as EclObject("sphere"). Hyphens +# are replaced with underscores to get valid Python identifiers. +if kenzo_installed(): + ecl_eval("(in-package :cat)") + ecl_eval("(setf *HOMOLOGY-VERBOSE* nil)") + for s in kenzo_names: + name = '__{}__'.format(s.replace('-', '_')) + exec('{} = EclObject("{}")'.format(name, s)) def Sphere(n): @@ -627,7 +646,7 @@ def differential(self, dim=None, comb=None): """ if dim is not None and comb is not None: cmbn_list = pairing(comb) - return KenzoObject(__dffr_aux_1__(self._kenzo, dim, cmbn_list)) + return KenzoObject(__dffr_aux1__(self._kenzo, dim, cmbn_list)) else: return KenzoChainComplexMorphism(__dffr_aux__(self._kenzo)) @@ -1121,14 +1140,14 @@ def SChainComplex(kchaincomplex, start=0, end=15): :: - sage: from sage.interfaces.kenzo import SChainComplex, Sphere - sage: S4 = Sphere(4) - sage: C = SChainComplex(S4) - sage: C + sage: from sage.interfaces.kenzo import SChainComplex, Sphere # optional - kenzo + sage: S4 = Sphere(4) # optional - kenzo + sage: C = SChainComplex(S4) # optional - kenzo + sage: C # optional - kenzo Chain complex with at most 3 nonzero terms over Integer Ring - sage: C._ascii_art_() + sage: C._ascii_art_() # optional - kenzo 0 <-- C_4 <-- 0 ... 0 <-- C_0 <-- 0 - sage: [C.homology(i) for i in range(6)] + sage: [C.homology(i) for i in range(6)] # optional - kenzo [Z, 0, 0, 0, Z, 0] """ matrices = {} From 0c4107c71fa6dc9ffbfd6cfcc6f222a4b4f4d972 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 28 May 2020 15:03:39 +1000 Subject: [PATCH 303/476] Using join and faster bool check in RAAG cohomology. --- src/sage/groups/raag.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index a4f210377d5..c7fd9437dff 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -698,14 +698,9 @@ def _repr_term(self, m): sage: y*w + x*z -e0*e2 + e1*e3 """ - if len(m) == 0: + if not m: return '1' - term = '' - for i in m: - if len(term) != 0: - term += '*' - term += 'e' + str(i) - return term + return '*'.join('e' + str(i) for i in m) def _ascii_art_term(self, m): r""" @@ -722,7 +717,7 @@ def _ascii_art_term(self, m): sage: ascii_art(y*w + 2*x*z) -e0/\e2 + 2*e1/\e3 """ - if len(m) == 0: + if not m: return ascii_art('1') wedge = '/\\' return ascii_art(*['e' + str(i) for i in m], sep=wedge) @@ -742,7 +737,7 @@ def _unicode_art_term(self, m): sage: unicode_art(y*w + x*z) -e0∧e2 + e1∧e3 """ - if len(m) == 0: + if not m: return unicode_art('1') import unicodedata wedge = unicodedata.lookup('LOGICAL AND') @@ -759,17 +754,12 @@ def _latex_term(self, m): sage: A = groups.misc.RightAngledArtin(C4) sage: H = A.cohomology() sage: H._latex_term((0,1,3)) - ' e_{0} \\wedge e_{1} \\wedge e_{3}' + 'e_{0} \\wedge e_{1} \\wedge e_{3}' """ - if len(m) == 0: + if not m: return '1' - term = '' from sage.misc.latex import latex - for i in m: - if len(term) != 0: - term += ' \\wedge' - term += ' e_{{{}}}'.format(latex(i)) - return term + return " \\wedge ".join('e_{{{}}}'.format(latex(i)) for i in m) def gen(self, i): """ From e5e50fd8a3a397a29576d36c850ee57d8c17224b Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Wed, 27 May 2020 23:38:36 -0600 Subject: [PATCH 304/476] 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 27b3e27ca0403ec920ae7c6d34b416f974f14506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 28 May 2020 13:57:21 +0200 Subject: [PATCH 305/476] Make docker versions compatible in GitLab CI there used to be a bug in docker:dind that we needed to work around by pinning its version. That's not necessary anymore. --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 22a4075b91e..677f02e7ba0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ # If you want to provide your own runners, make sure to tag them as follows: # * "big" (60GB of disk space are available) to make build-from-clean pass. -image: docker:latest +image: docker:stable stages: - build @@ -77,7 +77,7 @@ before_script: # better isolation. If you expect many builds to run simultaneously on a host, # conflicting tags can cause issues with a mounted DOCKER_HOST. services: -- docker:18.05.0-ce-dind +- docker:stable-dind # Build Sage and its documentation. # The build starts from the build artifacts of DEFAULT_ARTIFACT_BASE which is From c4d2974d25adbe1aa21b2cf7471fd14a7a08dd54 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 28 May 2020 21:10:41 +0900 Subject: [PATCH 306/476] Fix a bug in _singularities --- src/sage/schemes/curves/projective_curve.py | 31 ++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 592bb68dc65..052218063d4 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -2307,6 +2307,10 @@ def _singularities(self): sage: C = Curve(y^2*z^7 - x^9 - x*z^8) sage: C._singularities [(Point (x, z), [Place (1/y, 1/y*z^5 + 4*y*z^4 + 1/y^2*z)])] + sage: D = Curve(x) + sage: D._singularities + [] + """ S = self.ambient_space().coordinate_ring() to_F = self._lift_to_function_field @@ -2317,19 +2321,20 @@ def _singularities(self): places = [] for i in range(self.ngens()): denom = self._coordinate_functions[i] - funcs = [] - for p in S._first_ngens(i) + sing.defining_polynomials(): - f = to_F(p)/denom**p.degree() - if not f.is_zero(): - funcs.append(f) - - if funcs: - f = funcs.pop() - pls = f.zeros() - for f in funcs: - pls = [p for p in pls if f.valuation(p) > 0] - - places.extend(pls) + if denom: + funcs = [] + for p in S._first_ngens(i) + sing.defining_polynomials(): + f = to_F(p)/denom**p.degree() + if not f.is_zero(): + funcs.append(f) + + if funcs: + f = funcs.pop() + pls = f.zeros() + for f in funcs: + pls = [p for p in pls if f.valuation(p) > 0] + + places.extend(pls) # compute closed points below the places lying on the singular locus, # and then collect places lying on each closed points From cd4c06307cce805351e7c75037e4bd7c2ebe61c3 Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Thu, 28 May 2020 14:37:38 +0200 Subject: [PATCH 307/476] Trac #29749: correct package name for python37-urllib3 on Cygwin --- build/pkgs/cygwin.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cygwin.txt b/build/pkgs/cygwin.txt index 51c562cb9b9..635afe8f9c9 100644 --- a/build/pkgs/cygwin.txt +++ b/build/pkgs/cygwin.txt @@ -13,7 +13,7 @@ binutils make m4 # a system python is needed for downloading the sage packages, https://trac.sagemath.org/ticket/29090 -python37-urllib python37 +python37-urllib3 python37 perl perl-ExtUtils-MakeMaker tar From 2f0c99c35aab6fcf81ed257180ebd5f9bc261225 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Thu, 28 May 2020 18:57:27 +0200 Subject: [PATCH 308/476] 29716 rebasing and pyflakes hints --- src/sage/algebras/splitting_algebra.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 020cc3145d4..c54197b5845 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -36,16 +36,14 @@ from warnings import warn -from sage.structure.element import get_coercion_model from sage.misc.misc import verbose from sage.misc.cachefunc import cached_method -from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_domain, PolynomialQuotientRing_generic +from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_domain from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement - # ------------------------------------------------------------------------------------------------------------------ # Element class for the splitting algebra # -------------------------------------------------------------------------------------------------------- @@ -812,5 +810,5 @@ def create_roots(monic_polynomial, warning=True): if flatten: from sage.misc.flatten import flatten - return flatten([[r]*m for r, m in roots]) + return flatten([[rt]*m for rt, m in roots]) return roots From 3a634d0b79f38e8c6542aa7ba647d48889e4128f Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Thu, 28 May 2020 16:31:08 -0600 Subject: [PATCH 309/476] 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 1149ce49e157684a30a682e033148c1a706b6dbc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 29 May 2020 11:28:50 +1000 Subject: [PATCH 310/476] Using Features for Kenzo. --- src/sage/features/kenzo.py | 53 ++++++++++++++++++++++++++++++++++++ src/sage/interfaces/kenzo.py | 28 ++----------------- 2 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 src/sage/features/kenzo.py diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py new file mode 100644 index 00000000000..c3c68ede71b --- /dev/null +++ b/src/sage/features/kenzo.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +r""" +Check for Kenzo +""" + +from sage.libs.ecl import ecl_eval +from . import Feature, FeatureTestResult + +class Kenzo(Feature): + r""" + A :class:`sage.features.Feature` describing the presence of ``Kenzo``. + + EXAMPLES:: + + sage: from sage.features.kenzo import Kenzo + sage: Kenzo().is_present() # optional - kenzo + FeatureTestResult('Kenzo', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.kenzo import Kenzo + sage: isinstance(Kenzo(), Kenzo) + True + """ + Feature.__init__(self, name="Kenzo", spkg="kenzo", + url="https://github.com/miguelmarco/kenzo/") + + def _is_present(self): + r""" + Check whether Kenzo is installed and works. + + EXAMPLES:: + + sage: from sage.features.kenzo import Kenzo + sage: Kenzo()._is_present() # optional - kenzo + FeatureTestResult('Kenzo', True) + """ + # Redirection of ECL and Maxima stdout to /dev/null + # This is also done in the Maxima library, but we + # also do it here for redundancy. + ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream + (make-concatenated-stream) (make-broadcast-stream)))""") + ecl_eval("(setf original-standard-output *standard-output*)") + ecl_eval("(setf *standard-output* *dev-null*)") + + try: + ecl_eval("(require :kenzo)") + except RuntimeError: + return FeatureTestResult(self, False, reason="Unable to make ECL require kenzo") + return FeatureTestResult(self, True) + diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 58222b49a7e..c7463946a61 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -39,31 +39,7 @@ from sage.homology.simplicial_set import AbstractSimplex, SimplicialSet from sage.libs.ecl import EclObject, ecl_eval, EclListIterator - - -def kenzo_installed(): - """ - True if Kenzo is installed. - - EXAMPLES:: - - sage: from sage.interfaces.kenzo import kenzo_installed - sage: kenzo_installed() # random - False - """ - # Redirection of ECL and Maxima stdout to /dev/null - # This is also done in the Maxima library, but we - # also do it here for redundancy. - ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream - (make-concatenated-stream) (make-broadcast-stream)))""") - ecl_eval("(setf original-standard-output *standard-output*)") - ecl_eval("(setf *standard-output* *dev-null*)") - - try: - ecl_eval("(require :kenzo)") - except RuntimeError: - return False - return True +from sage.features.kenzo import Kenzo # defining the auxiliary functions as wrappers over the kenzo ones @@ -131,7 +107,7 @@ def kenzo_installed(): # following defines __s__, a wrapper for a Kenzo function. For # example __sphere__ is defined as EclObject("sphere"). Hyphens # are replaced with underscores to get valid Python identifiers. -if kenzo_installed(): +if Kenzo().is_present(): ecl_eval("(in-package :cat)") ecl_eval("(setf *HOMOLOGY-VERBOSE* nil)") for s in kenzo_names: From 57bc9f6d68da9c4e9a596d942562e03f4d76dc78 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 29 May 2020 11:39:20 +1000 Subject: [PATCH 311/476] Attempt to fix pdf build, plus other misc fixes. --- src/doc/en/reference/references/index.rst | 2 +- src/sage/algebras/catalog.py | 2 +- src/sage/combinat/diagram_algebras.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 17fbacb9f00..e2d8fda8a6a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2863,7 +2863,7 @@ REFERENCES: .. [ILZ2018] \K. Iohara, G. Lehrer, and R. Zhang. *Schur-Weyl duality for certain infinite dimensional* - `U_q(\mathfrak{sl}_2`-*modules*. + `U_q(\mathfrak{sl}_2)`-*modules*. Preprint, :arxiv:`1811.01325` (2018). .. [IR1990] \K. Ireland and M. Rosen, *A Classical Introduction to diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 261d7667fb3..76a59c355cc 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -12,8 +12,8 @@ - :class:`algebras.ArikiKoike ` - :class:`algebras.AskeyWilson ` -- :class:`algebras.Brauer ` - :class:`algebras.Blob ` +- :class:`algebras.Brauer ` - :class:`algebras.Clifford ` - :class:`algebras.ClusterAlgebra ` - :class:`algebras.Descent ` diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index fae2a9a1040..a8a52ff6743 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -3747,7 +3747,7 @@ def TL_diagram_ascii_art(diagram, use_unicode=False, blobs=[]): INPUT: - ``diagram`` -- a list of pairs of matchings of the set - `\{-1, \dotsc, -n, 1, \dotsc, n\}` + `\{-1, \ldots, -n, 1, \ldots, n\}` - ``use_unicode`` -- (default: ``False``): whether or not to use unicode art instead of ascii art - ``blobs`` -- (optional) a list of matchings with blobs on them From 1267467269fc838d5c385e13973b6791b1dc3d79 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 29 May 2020 15:07:11 +1000 Subject: [PATCH 312/476] 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 5ea214fd1fb24e82aa614925c8d208099a428470 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 29 May 2020 11:55:40 +0200 Subject: [PATCH 313/476] 29716: rebase to 9.2.beta0 and some style fixes --- src/sage/algebras/splitting_algebra.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index c54197b5845..676fc54615d 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -242,7 +242,7 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): warn('Assuming %s to be an integral domain!' %(base_ring)) - if deg < 1 : + if deg < 1: raise ValueError( "the degree of the polynomial must positive" ) self._splitting_roots = [] @@ -316,7 +316,7 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): verbose("final ring defined splitting_roots: %s" %(self._splitting_roots)) - if deg == 2 : + if deg == 2: coefficients = monic_polynomial.coefficients(sparse=False) lin_coeff = coefficients[1] self._splitting_roots.append(-lin_coeff - first_root) @@ -502,7 +502,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): im_gens_start = [img for img in im_gens if im_gens.index(img) < num_gens] im_gens_end = [img for img in im_gens if im_gens.index(img) >= num_gens] - if len(im_gens_end) == 0 : + if len(im_gens_end) == 0: return super(SplittingAlgebra, self).hom(im_gens, codomain=codomain, check=check, base_map=base_map) verbose('base %s im_gens_end %s codomain %s check %s base_map %s' %(base_ring, im_gens_end, codomain, check, base_map)) @@ -778,12 +778,12 @@ def create_roots(monic_polynomial, warning=True): except (TypeError, ValueError, NotImplementedError): pass - if len(root_list) == 0 : + if len(root_list) == 0: # ------------------------------------------------------------------------------ # no roots found: find roots in an appropriate extension ring # ------------------------------------------------------------------------------ verbose("no roots in base_ring") - if len(name_list) > deg_pol -1 : + if len(name_list) > deg_pol -1: name_list = [name_list[i] for i in range(deg_pol-1 )] roots = create_roots(monic_polynomial, warning=warning) @@ -799,7 +799,7 @@ def create_roots(monic_polynomial, warning=True): for r, m in root_list: divisor *= (h - r)**m q, r = monic_polynomial.quo_rem(divisor) - if len(name_list) > deg_pol - num_roots -1 : + if len(name_list) > deg_pol - num_roots -1: name_list = [name_list[i] for i in range(deg_pol - num_roots -1 )] verbose("%d root found in base ring, now solving %s" %(num_roots,q)) missing_roots = create_roots(q, warning=True) From b0553e58a3e717d630a7bd89d438318a7c5af639 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 29 May 2020 12:46:27 +0100 Subject: [PATCH 314/476] A few little changes --- src/sage/combinat/gelfand_tsetlin_patterns.py | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index ae1de2faa15..d1a3070958a 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -511,9 +511,12 @@ def Tokuyama_coefficient(self, name='t'): def bender_knuth_involution(self,i): r""" - Return the image of ''self'' under the 'i'-th Bender-Knuth involution. + Return the image of ``self`` under the `i`-th Bender-Knuth involution. - If the triangle 'G' has size 'n' then this is defined for '0 < i < n'. + If the triangle ``self`` has size `n` then this is defined for `0 < i < n`. + + The entries of ``self`` can take values in any ordered ring. Usually, + this will be the integers but can also be the rationals or the real numbers. This implements the construction of the Bender-Knuth involution using toggling due to Berenstein-Kirillov. @@ -526,6 +529,10 @@ def bender_knuth_involution(self,i): sage: G.bender_knuth_involution(2) [[5, 3, 2, 1, 0], [4, 3, 2, 0], [4, 2, 1], [4, 1], [3]] + sage: G = GelfandTsetlinPattern([[3,2,0],[2.2,0],[2]]) + sage: G.bender_knuth_involution(2) + [[3, 2, 0], [2.80000000000000, 2], [2]] + TESTS:: sage: all(all( G.bender_knuth_involution(i).to_tableau() == G.to_tableau().bender_knuth_involution(i) \ @@ -543,33 +550,34 @@ def bender_knuth_involution(self,i): ValueError: must have 0 < 3 < 3 """ - from copy import copy + #from copy import copy n = len(self) def toggle(i,j): - """ - Return the toggle of entry 'G[i][j]' in a Gelfand-Tsetlin pattern, 'G'. - """ - if i == n-1: - return self[n-2][0]+self[n-2][1]-self[n-1][0] - - if j == 0: - left = self[i-1][0] - else: - left = min(self[i-1][j], self[i+1][j-1]) - if j == n-i-1: - right = self[i-1][j+1] - else: - right = max(self[i-1][j+1], self[i+1][j]) + """ + Return the toggle of entry 'G[i][j]' in a Gelfand-Tsetlin pattern, 'G'. + """ + if i == n-1: + return self[n-2][0]+self[n-2][1]-self[n-1][0] + + if j == 0: + left = self[i-1][0] + else: + left = min(self[i-1][j], self[i+1][j-1]) + if j == n-i-1: + right = self[i-1][j+1] + else: + right = max(self[i-1][j+1], self[i+1][j]) - return left + right - self[i][j] + return left + right - self[i][j] if not 0 < i < n: raise ValueError(f"must have 0 < {i} < {n}") r = n-i - result = copy(self) - result[r] = [toggle(r,s) for s in range(i)] - return result + P = self.parent() + data = [list(row) for row in self] + data[r] = [toggle(r,s) for s in range(i)] + return P.element_class(P, data) class GelfandTsetlinPatterns(UniqueRepresentation, Parent): """ From 4747bd6d65d2ed3cd25c35a22fe0dcb0f0908693 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 29 May 2020 13:31:21 +0100 Subject: [PATCH 315/476] 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 316/476] 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 317/476] 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 fd2eac0367395d87447b6308f2724d6565c6ef2d Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 29 May 2020 21:33:33 +0200 Subject: [PATCH 318/476] 29759: replace string_types by str --- src/sage/interfaces/macaulay2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index f6f7df8dc7f..a2e93ebb688 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -857,7 +857,7 @@ def _macaulay2_input_ring(self, base_ring, vars, order='GRevLex'): sage: macaulay2._macaulay2_input_ring(R.base_ring(), R.gens(), 'Lex') # optional - macaulay2 'sage...[symbol x, MonomialSize=>16, MonomialOrder=>Lex]' """ - if not isinstance(base_ring, string_types): + if not isinstance(base_ring, str): base_ring = self(base_ring).name() varstr = str(vars)[1:-1].rstrip(',') From f92fd0807a470bdc0a4cbdcd73aa284660b3533e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 29 May 2020 12:51:13 -0700 Subject: [PATCH 319/476] trac 27880: fix spkg-install.in problems, explicitly require :kenzo --- build/pkgs/kenzo/spkg-install.in | 12 +++++++----- src/sage/interfaces/kenzo.py | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/build/pkgs/kenzo/spkg-install.in b/build/pkgs/kenzo/spkg-install.in index 294a543d7e7..3c8e5946547 100644 --- a/build/pkgs/kenzo/spkg-install.in +++ b/build/pkgs/kenzo/spkg-install.in @@ -1,15 +1,17 @@ cd src - - # create a short lisp file with the instructions to load kenzo from ecl # This will compile the lisp files since it is the first time they are loaded ecl < compile.lisp -echo "moving kenzo--all-systems.fasb to $SAGE_LOCAL/lib/ecl/kenzo.fas" -sdh_install -T kenzo--all-systems.fasb $SAGE_LOCAL/lib/ecl/kenzo.fas - +# Install Kenzo into ECL's library directory (installation procedure +# copied from Maxima's spkg-install.in file): +ECLLIB=`ecl -eval "(princ (SI:GET-LIBRARY-PATHNAME))" -eval "(quit)"` +echo +echo "Now installing Kenzo as '$ECLLIB/kenzo.fas'..." +cp -f kenzo--all-systems.fasb "$ECLLIB/kenzo.fas" \ + || sdh_die "Failed to install 'kenzo--all-systems.fasb' as '$ECLLIB/kenzo.fas'." if [ $? -ne 0 ]; then echo >&2 "Error installing Kenzo." diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index c7463946a61..43142421140 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -108,6 +108,7 @@ # example __sphere__ is defined as EclObject("sphere"). Hyphens # are replaced with underscores to get valid Python identifiers. if Kenzo().is_present(): + ecl_eval("(require :kenzo)") ecl_eval("(in-package :cat)") ecl_eval("(setf *HOMOLOGY-VERBOSE* nil)") for s in kenzo_names: From 0942d3b700614cb819491e423984f1f4c09dafc9 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 30 May 2020 09:21:29 +0100 Subject: [PATCH 320/476] 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 321/476] 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 322/476] 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 cc4fd9c1b4277eae66345802e138067fdc834e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 30 May 2020 13:27:51 +0200 Subject: [PATCH 323/476] fix one doc glitch in spanning tree --- src/sage/graphs/spanning_tree.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 1572f35bac4..ec05b0a4040 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -286,6 +286,7 @@ def kruskal_iterator(G, wfunction=None, bint check=False): weighted=G.weighted(), weight_function=wfunction) + def kruskal_iterator_from_edges(edges, union_find, weighted=False, weight_function=None): """ Return an iterator implementation of Kruskal algorithm on list of edges. @@ -342,6 +343,7 @@ def kruskal_iterator_from_edges(edges, union_find, weighted=False, weight_functi if union_find.number_of_subsets() == 1: return + def filter_kruskal(G, threshold=10000, weight_function=None, bint check=False): """ Minimum spanning tree using Filter Kruskal algorithm. @@ -418,6 +420,7 @@ def filter_kruskal(G, threshold=10000, weight_function=None, bint check=False): """ return list(filter_kruskal_iterator(G, threshold=threshold, weight_function=weight_function, check=check)) + def filter_kruskal_iterator(G, threshold=10000, weight_function=None, bint check=False): r""" Return an iterator implementation of Filter Kruskal's algorithm. @@ -436,7 +439,7 @@ def filter_kruskal_iterator(G, threshold=10000, weight_function=None, bint check EXAMPLES: The edges of a minimum spanning tree of ``G``, if one exists, otherwise - returns the empty list. + returns the empty list. :: sage: from sage.graphs.spanning_tree import filter_kruskal_iterator sage: G = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:{6:25, 7:24}}) @@ -791,6 +794,7 @@ cpdef boruvka(G, wfunction=None, bint check=False, bint by_weight=True): return T + @cython.binding(True) def random_spanning_tree(self, output_as_graph=False): r""" From 620d6ada8559bb06e5bfaa9b98d40f1604cd474d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 30 May 2020 12:43:29 +0100 Subject: [PATCH 324/476] Changed line break to ellipsis --- src/sage/combinat/gelfand_tsetlin_patterns.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index d1a3070958a..a4da99c8eed 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -535,8 +535,8 @@ def bender_knuth_involution(self,i): TESTS:: - sage: all(all( G.bender_knuth_involution(i).to_tableau() == G.to_tableau().bender_knuth_involution(i) \ - for i in range(1,len(G)) ) for G in GelfandTsetlinPatterns(top_row=[3,3,3,0,0])) + sage: all(all( G.bender_knuth_involution(i).to_tableau() == G.to_tableau().bender_knuth_involution(i) + ....: for i in range(1,len(G)) ) for G in GelfandTsetlinPatterns(top_row=[3,3,3,0,0])) True sage: G = GelfandTsetlinPattern([[2,1,0],[1,0],[0]]) From a2a246c18c2acb897c266ae3ab1bfe88253ab0ba Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 12:46:56 -0400 Subject: [PATCH 325/476] 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 326/476] 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 327/476] 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 328/476] 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 329/476] 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 330/476] 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 331/476] 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 332/476] 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 333/476] 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 334/476] 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 335/476] 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 80d2fbe5a3ab4efb9e645ce25b9a66770a681b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 30 May 2020 15:13:50 +0200 Subject: [PATCH 336/476] some details in doc of Hasse diagrams --- src/sage/combinat/posets/hasse_diagram.py | 70 ++++++++++++----------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index de9c28a785a..082bffcbd3b 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -99,7 +99,7 @@ def linear_extension(self): r""" Return a linear extension - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]}) @@ -113,7 +113,7 @@ def linear_extensions(self): r""" Return an iterator over all linear extensions. - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]}) @@ -144,7 +144,7 @@ def greedy_linear_extensions_iterator(self): [0, 1, 2, 3, 4] [0, 2, 3, 1, 4] - TESTS: + TESTS:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: list(HasseDiagram({}).greedy_linear_extensions_iterator()) @@ -244,7 +244,7 @@ def is_linear_extension(self, lin_ext=None): r""" Test if an ordering is a linear extension. - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[1,2],1:[3],2:[3],3:[]}) @@ -268,7 +268,7 @@ def cover_relations_iterator(self): r""" Iterate over cover relations. - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[2,3], 1:[3,4], 2:[5], 3:[5], 4:[5]}) @@ -282,7 +282,7 @@ def cover_relations(self): r""" Return the list of cover relations. - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[2,3], 1:[3,4], 2:[5], 3:[5], 4:[5]}) @@ -293,15 +293,15 @@ def cover_relations(self): def is_lequal(self, i, j): """ - Return True if i is less than or equal to j in the poset, and - False otherwise. + Return ``True`` if i is less than or equal to j in the poset, and + ``False`` otherwise. .. note:: If the :meth:`lequal_matrix` has been computed, then this method is redefined to use the cached data (see :meth:`_alternate_is_lequal`). - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) @@ -321,10 +321,10 @@ def is_lequal(self, i, j): def is_less_than(self, x, y): r""" - Return True if ``x`` is less than or equal to ``y`` in the - poset, and False otherwise. + Return ``True`` if ``x`` is less than or equal to ``y`` in the + poset, and ``False`` otherwise. - TESTS:: + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0:[2], 1:[2], 2:[3], 3:[4], 4:[]}) @@ -342,8 +342,7 @@ def is_less_than(self, x, y): """ if x == y: return False - else: - return self.is_lequal(x, y) + return self.is_lequal(x, y) def is_gequal(self, x, y): r""" @@ -443,7 +442,7 @@ def bottom(self): def has_bottom(self): """ - Return True if the poset has a unique minimal element. + Return ``True`` if the poset has a unique minimal element. EXAMPLES:: @@ -492,8 +491,8 @@ def has_top(self): def is_bounded(self): """ - Return True if the poset contains a unique maximal element and a - unique minimal element, and False otherwise. + Return ``True`` if the poset contains a unique maximal element and a + unique minimal element, and ``False`` otherwise. EXAMPLES:: @@ -508,7 +507,7 @@ def is_bounded(self): def is_chain(self): """ - Return True if the poset is totally ordered, and False otherwise. + Return ``True`` if the poset is totally ordered, and ``False`` otherwise. EXAMPLES:: @@ -556,6 +555,10 @@ def dual(self): """ Return a poset that is dual to the given poset. + This means that it has the same elements but opposite order. + The elements are renumbered to ensure that ``range(n)`` + is a linear extension. + EXAMPLES:: sage: P = posets.IntegerPartitions(4) @@ -631,8 +634,9 @@ def _alternate_interval(self, x, y): def interval(self, x, y): r""" Return a list of the elements `z` of ``self`` such that - `x \leq z \leq y`. The order is that induced by the - ordering in ``self.linear_extension``. + `x \leq z \leq y`. + + The order is that induced by the ordering in ``self.linear_extension``. INPUT: @@ -657,9 +661,9 @@ def interval(self, x, y): def open_interval(self, x, y): """ - Return a list of the elements `z` of ``self`` such that - `x < z < y`. The order is that induced by the ordering in - ``self.linear_extension``. + Return a list of the elements `z` of ``self`` such that `x < z < y`. + + The order is that induced by the ordering in ``self.linear_extension``. EXAMPLES:: @@ -828,7 +832,7 @@ def rank(self, element=None): def is_ranked(self): r""" - Return True if the poset is ranked, and False otherwise. + Return ``True`` if the poset is ranked, and ``False`` otherwise. A poset is *ranked* if it admits a rank function. For more information about the rank function, see :meth:`~rank_function` @@ -847,7 +851,7 @@ def is_ranked(self): def covers(self, x, y): """ - Return True if y covers x and False otherwise. + Return ``True`` if y covers x and ``False`` otherwise. EXAMPLES:: @@ -1428,8 +1432,10 @@ def _meet(self): def meet_matrix(self): r""" - Return the matrix of meets of ``self``. The ``(x,y)``-entry of - this matrix is the meet of ``x`` and ``y`` in ``self``. + Return the matrix of meets of ``self``. + + The ``(x,y)``-entry of this matrix is the meet of ``x`` and + ``y`` in ``self``. This algorithm is modelled after the algorithm of Freese-Jezek-Nation (p217). It can also be found on page 140 of [Gec81]_. @@ -2100,7 +2106,7 @@ def are_incomparable(self, i, j): INPUT: - - ``i``, ``j`` -- vertices of this Hasse diagram + - ``i``, ``j`` -- vertices of this Hasse diagram EXAMPLES:: @@ -2140,7 +2146,7 @@ def antichains(self, element_class=list): INPUT: - - ``element_class`` -- (default:list) an iterable type + - ``element_class`` -- (default:list) an iterable type EXAMPLES:: @@ -2160,8 +2166,6 @@ def antichains(self, element_class=list): sage: TestSuite(A).run() - TESTS:: - sage: A = Poset()._hasse_diagram.antichains() sage: list(A) [[]] @@ -2209,7 +2213,7 @@ def chains(self, element_class=list, exclude=None): [[], [0], [0, 1], [0, 2], [1], [2]] The ``element_class`` keyword determines how the chains are - being returned: + being returned:: sage: P = Poset({1: [2, 3], 2: [4]}) sage: list(P._hasse_diagram.chains(element_class=tuple)) @@ -2217,7 +2221,7 @@ def chains(self, element_class=list, exclude=None): sage: list(P._hasse_diagram.chains()) [[], [0], [0, 1], [0, 1, 2], [0, 2], [0, 3], [1], [1, 2], [2], [3]] - (Note that taking the Hasse diagram has renamed the vertices.) + (Note that taking the Hasse diagram has renamed the vertices.) :: sage: list(P._hasse_diagram.chains(element_class=tuple, exclude=[0])) [(), (1,), (1, 2), (2,), (3,)] From 144ecaba04aa65878ebbc6261f636cd550a0f9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 30 May 2020 20:53:02 +0200 Subject: [PATCH 337/476] get rid of _cmp_ for polynomials --- .../rings/polynomial/multi_polynomial_libsingular.pyx | 9 ++++----- src/sage/rings/polynomial/pbori.pyx | 6 +++--- src/sage/rings/polynomial/plural.pyx | 10 +++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ab1879650e4..779ad041d7f 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -2165,10 +2165,9 @@ cdef class MPolynomial_libsingular(MPolynomial): """ return self._hash_c() - cpdef int _cmp_(left, right) except -2: + cpdef _richcmp_(left, right, int op): """ - Compare left and right and return -1, 0, and 1 for <,==, and > - respectively. + Compare left and right. EXAMPLES:: @@ -2218,11 +2217,11 @@ cdef class MPolynomial_libsingular(MPolynomial): True """ if left is right: - return 0 + return rich_to_bool(op, 0) cdef poly *p = (left)._poly cdef poly *q = (right)._poly cdef ring *r = (left)._parent_ring - return singular_polynomial_cmp(p, q, r) + return rich_to_bool(op, singular_polynomial_cmp(p, q, r)) cpdef _add_(left, right): """ diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 0ea74a744ce..e4d6fb4a415 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -207,7 +207,7 @@ from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence from sage.structure.element import coerce_binop from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.richcmp cimport richcmp, richcmp_not_equal +from sage.structure.richcmp cimport richcmp, richcmp_not_equal, rich_to_bool from sage.categories.action cimport Action @@ -2241,7 +2241,7 @@ cdef class BooleanMonomial(MonoidElement): gens = self._parent.gens() return self._parent, (tuple(gens.index(x) for x in self.variables()),) - cpdef int _cmp_(left, right) except -2: + cpdef _richcmp_(left, right, int op): """ Compare BooleanMonomial objects. @@ -2267,7 +2267,7 @@ cdef class BooleanMonomial(MonoidElement): """ cdef int res res = left._pbmonom.compare((right)._pbmonom) - return res + return rich_to_bool(op, res) def _repr_(self): """ diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 42001d4fcfa..99cf3a2963f 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -133,6 +133,7 @@ from sage.rings.polynomial.polydict import ETuple from sage.rings.ring import check_default_category from sage.structure.element cimport CommutativeRingElement, Element, ModuleElement, RingElement from sage.structure.factory import UniqueFactory +from sage.structure.richcmp cimport rich_to_bool from sage.structure.parent cimport Parent from sage.structure.parent_gens cimport ParentWithGens from sage.rings.polynomial.term_order import TermOrder @@ -1469,10 +1470,9 @@ cdef class NCPolynomial_plural(RingElement): """ return self._hash_c() - cpdef int _cmp_(left, right) except -2: + cpdef _richcmp_(left, right, int op): """ - Compare left and right and return -1, 0, and 1 for <,==, and > - respectively. + Compare left and right. EXAMPLES:: @@ -1515,11 +1515,11 @@ cdef class NCPolynomial_plural(RingElement): True """ if left is right: - return 0 + return rich_to_bool(op, 0) cdef poly *p = (left)._poly cdef poly *q = (right)._poly cdef ring *r = (left._parent)._ring - return singular_polynomial_cmp(p, q, r) + return rich_to_bool(op, singular_polynomial_cmp(p, q, r)) cpdef _add_(left, right): """ From e4d3598ea1e261cd7db9ba71fdd7da9b5b23746a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 31 May 2020 16:10:48 +1000 Subject: [PATCH 338/476] 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 339/476] 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 c75f16cd575c5be1e82b2f7a80ef0bae1e20595b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 31 May 2020 11:47:56 +0200 Subject: [PATCH 340/476] remove very old deprecated stuff in fast_callable and fast_eval --- src/sage/ext/fast_callable.pyx | 7 +------ src/sage/ext/fast_eval.pyx | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 94e2928525b..86033d983be 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -311,7 +311,6 @@ from sage.structure.element cimport parent def fast_callable(x, domain=None, vars=None, - _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=False, expect_one_var=False): r""" Given an expression x, compile it into a form that can be quickly @@ -481,11 +480,7 @@ def fast_callable(x, domain=None, vars=None, if len(vars) == 0: vars = ['EXTRA_VAR0'] else: - if _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality: - from sage.misc.superseded import deprecation - deprecation(5413, "Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)") - else: - raise ValueError("List of variables must be specified for symbolic expressions") + raise ValueError("List of variables must be specified for symbolic expressions") from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing if is_PolynomialRing(x.parent()) or is_MPolynomialRing(x.parent()): diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index 0743f3052ca..1d2c1bf4470 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -1399,7 +1399,8 @@ def fast_float(f, *vars, old=None, expect_one_var=False): if old: return f._fast_float_(*vars) else: - return fast_callable(f, vars=vars, domain=float, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=True, expect_one_var=expect_one_var) + return fast_callable(f, vars=vars, domain=float, + expect_one_var=expect_one_var) except AttributeError: pass From c2e4da8be64e61372d4bb2f552a7ae678cc5d433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 31 May 2020 13:08:07 +0200 Subject: [PATCH 341/476] pyflakes cleanup for sage/misc --- src/sage/misc/remote_file.py | 1 - src/sage/misc/sage_timeit.py | 2 +- src/sage/misc/sageinspect.py | 1 - src/sage/misc/sphinxify.py | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index 5d99a2e8670..297c5376e55 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -3,7 +3,6 @@ from __future__ import absolute_import import os -import sys from urllib.request import Request, urlopen diff --git a/src/sage/misc/sage_timeit.py b/src/sage/misc/sage_timeit.py index 13035cc5134..f82300651dc 100644 --- a/src/sage/misc/sage_timeit.py +++ b/src/sage/misc/sage_timeit.py @@ -201,7 +201,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec sage: gc.isenabled() True """ - import time, math + import math import timeit as timeit_ import sage.repl.interpreter as interpreter diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 6251ec5742c..635415dd5f5 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -118,7 +118,6 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return import inspect import functools import os -import sys import tokenize import re EMBEDDED_MODE = False diff --git a/src/sage/misc/sphinxify.py b/src/sage/misc/sphinxify.py index ab0de0a7b66..4077044624d 100644 --- a/src/sage/misc/sphinxify.py +++ b/src/sage/misc/sphinxify.py @@ -158,7 +158,6 @@ def sphinxify(docstring, format='html'): if __name__ == '__main__': - import sys if len(sys.argv) == 2: print(sphinxify(sys.argv[1])) else: From 762cacef83a0c8328d53bda9359ab2fc59e75a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 31 May 2020 13:14:17 +0200 Subject: [PATCH 342/476] one more pyflakes fix --- src/sage/doctest/control.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 8073a2373fe..cd771ae279a 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -7,8 +7,7 @@ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 David Roe # Robert Bradshaw # William Stein @@ -18,11 +17,17 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import, division, print_function -import random, os, sys, time, json, re, types +import random +import os +import sys +import time +import json +import re +import types import sage.misc.flatten from sage.structure.sage_object import SageObject from sage.env import DOT_SAGE, SAGE_LIB, SAGE_SRC, SAGE_LOCAL, SAGE_EXTCODE @@ -626,7 +631,6 @@ def test_safe_directory(self, dir=None): ... RuntimeError: refusing to run doctests... """ - import os import stat is_world_writeable = bool(os.stat(dir or os.getcwd()).st_mode & stat.S_IWOTH) if is_world_writeable: 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 343/476] 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 344/476] 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 345/476] 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 346/476] 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 347/476] 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 47937760b86c79b3b58a38ab0827ca8d5587b4ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 31 May 2020 20:02:59 +0200 Subject: [PATCH 348/476] tiny details --- src/sage/doctest/control.py | 3 ++- src/sage/misc/sphinxify.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index cd771ae279a..a90b45981bb 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -1126,7 +1126,8 @@ def run_val_gdb(self, testing=False): os.putenv('CYSIGNALS_CRASH_LOGS', tmp_dir("crash_logs_")) init_cysignals() - import signal, subprocess + import signal + import subprocess p = subprocess.Popen(cmd, shell=True) if opt.timeout > 0: signal.alarm(opt.timeout) diff --git a/src/sage/misc/sphinxify.py b/src/sage/misc/sphinxify.py index 4077044624d..d3db30be44b 100644 --- a/src/sage/misc/sphinxify.py +++ b/src/sage/misc/sphinxify.py @@ -107,8 +107,8 @@ def sphinxify(docstring, format='html'): """) staticdir = os.path.join(confdir, 'static') os.makedirs(staticdir) - with open(os.path.join(staticdir, 'empty'), 'w') as filed: pass - + with open(os.path.join(staticdir, 'empty'), 'w') as filed: + pass with open(os.path.join(srcdir, 'docutils.conf'), 'w') as filed: filed.write(r""" [parsers] From 51824a638343fa3fd1eba23fb77cfcdbc910a8a9 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 19:11:34 -0400 Subject: [PATCH 349/476] 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 b05bed81730982752805c1bae629782d94fd7aff Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 1 Jun 2020 10:21:23 +0900 Subject: [PATCH 350/476] Add tangent_line() and line_through() methods --- src/sage/schemes/affine/affine_space.py | 91 ++++++++++++++++++- src/sage/schemes/affine/affine_subscheme.py | 58 ++++++++++++ src/sage/schemes/curves/affine_curve.py | 62 ++++++++++++- src/sage/schemes/curves/projective_curve.py | 28 ++++++ .../schemes/projective/projective_space.py | 33 ++++++- 5 files changed, 268 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 0c847dbea65..4e7c65a283e 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -957,6 +957,21 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): else: raise ValueError("keyword 'kind' must have a value of either 'first' or 'second'") + def origin(self): + """ + Return the rational point at the origin of this affine space. + + EXAMPLES:: + + sage: A. = AffineSpace(QQ, 3) + sage: A.origin() + (0, 0, 0) + sage: _ == A(0,0,0) + True + + """ + return self([0 for i in range(self.ngens())]) + class AffineSpace_field(AffineSpace_generic): def _point(self, *args, **kwds): @@ -1125,7 +1140,7 @@ def curve(self,F): INPUT: - ``F`` -- a polynomial, or a list or tuple of polynomials in - the coordinate ring of this affine space. + the coordinate ring of this affine space EXAMPLES:: @@ -1136,6 +1151,80 @@ def curve(self,F): from sage.schemes.curves.constructor import Curve return Curve(F, self) + def line_through(self, p, q): + """ + Return the line through ``p`` and ``q``. + + INPUT: + + - ``p``, ``q`` -- distinct rational points of the affine space + + EXAMPLES:: + + sage: A3. = AffineSpace(3, QQ) + sage: p1 = A3(1, 2, 3) + sage: p2 = A3(4, 5, 6) + sage: A3.line_through(p1, p2) + Affine Curve over Rational Field defined by -1/6*x + 1/6*y - 1/6, + -1/6*x + 1/6*z - 1/3, -1/6*y + 1/6*z - 1/6, -1/6*x + 1/3*y - 1/6*z + sage: L = _ + sage: L(p1) + (1, 2, 3) + sage: L(p2) + (4, 5, 6) + sage: A3.line_through(p1, p1) + Traceback (most recent call last): + ... + ValueError: not distinct points + + """ + if p == q: + raise ValueError("not distinct points") + + proj = self.projective_embedding(0) + P = proj.codomain() + return P.line_through(proj(p), proj(q)).affine_patch(0, self) + + def translation(self, p, q=None): + """ + Return the automorphism of the affine space translating ``p`` to the origin. + + If ``q`` is given, the automorphism translates ``p`` to ``q``. + + INPUT: + + - ``p`` -- a rational point + + - ``q`` -- (default: ``None``) a rational point + + EXAMPLES:: + + sage: A. = AffineSpace(QQ, 3) + sage: p = A(1,2,3) + sage: q = A(4,5,6) + sage: A.translation(p, q) + Scheme endomorphism of Affine Space of dimension 3 over Rational Field + Defn: Defined on coordinates by sending (x, y, z) to + (x + 3, y + 3, z + 3) + sage: phi = A.translation(p) + sage: psi = A.translation(A.origin(), q) + sage: psi * phi + Scheme endomorphism of Affine Space of dimension 3 over Rational Field + Defn: Defined on coordinates by sending (x, y, z) to + (x + 3, y + 3, z + 3) + sage: psi * phi == A.translation(p, q) + True + + """ + gens = self.gens() + + if q is not None: + v = [cp - cq for cp, cq in zip(p, q)] + else: + v = [cp for cp in p] + + return self._morphism(self.Hom(self), [x - c for x, c in zip(gens, v)]) + class AffineSpace_finite_field(AffineSpace_field): def _point(self, *args, **kwds): diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index b5a0435b77c..1f7bc652234 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -22,6 +22,7 @@ from sage.categories.fields import Fields from sage.interfaces.all import singular +from sage.modules.all import vector from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from .affine_morphism import SchemeMorphism_polynomial_affine_subscheme_field @@ -537,3 +538,60 @@ def _morphism(self, *args, **kwds): (x*y : x : y) """ return SchemeMorphism_polynomial_affine_subscheme_field(*args, **kwds) + + def tangent_space(self, p): + """ + Return the tangent space at the point ``p``. + + The points of the tangent space are the tangent vectors at ``p``. + + INPUT: + + - ``p`` -- a rational point + + EXAMPLES:: + + sage: A3. = AffineSpace(3, QQ) + sage: X = A3.subscheme(z-x*y) + sage: X.tangent_space(A3.origin()) + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: + z + sage: X.tangent_space(X(1,1,1)) + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: + -x - y + z + + Tangent space at a point may have higher dimension than the dimension + of the point. :: + + sage: C = Curve([x + y + z, x^2 - y^2*z^2 + z^3]) + sage: C.singular_points() + [(0, 0, 0)] + sage: p = C(0,0,0) + sage: C.tangent_space(p) + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: + x + y + z + sage: _.dimension() + 2 + sage: q = C(1,0,-1) + sage: C.tangent_space(q) + Closed subscheme of Affine Space of dimension 3 over Rational Field + defined by: + x + y + z, + 2*x + 3*z + sage: _.dimension() + 1 + + """ + A = self.ambient_space() + R = A.coordinate_ring() + gens = R.gens() + + J = self.Jacobian_matrix() + Jp = J.apply_map( lambda f: f.subs(dict(zip(gens, list(p)))) ) + I = [f for f in Jp * vector(gens) if f] + + return A.subscheme(R.ideal(I)) + diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index c5384f08387..9e511f44514 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -117,7 +117,8 @@ from sage.rings.infinity import infinity from sage.schemes.affine.affine_space import AffineSpace, is_AffineSpace -from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine +from sage.schemes.affine.affine_subscheme import (AlgebraicScheme_subscheme_affine, + AlgebraicScheme_subscheme_affine_field) from .curve import Curve_generic @@ -785,7 +786,7 @@ def rational_parameterization(self): return H([para[1]/para[0], para[2]/para[0]]) -class AffineCurve_field(AffineCurve): +class AffineCurve_field(AffineCurve, AlgebraicScheme_subscheme_affine_field): """ Affine curves over fields. """ @@ -1600,6 +1601,63 @@ def extension(self): p_maps = [res[i][2] for i in range(len(res))] return tuple([tuple(patches), tuple(t_maps), tuple(p_maps)]) + def tangent_line(self, p): + """ + Return the tangent line at the point ``p``. + + INPUT: + + - ``p`` -- a rational point of the curve + + EXAMPLES:: + + sage: A3. = AffineSpace(3, QQ) + sage: C = Curve([x + y + z, x^2 - y^2*z^2 + z^3]) + sage: p = C(0,0,0) + sage: C.tangent_line(p) + Traceback (most recent call last): + ... + ValueError: the curve is not smooth at (0, 0, 0) + sage: p = C(1,0,-1) + sage: C.tangent_line(p) + Affine Curve over Rational Field defined by x + y + z, 2*x + 3*z + 1 + + We check that the tangent line at ``p`` is the tangent space at ``p``, + translated to ``p``. :: + + sage: Tp = C.tangent_space(p) + sage: Tp + Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: + x + y + z, + 2*x + 3*z + sage: phi = A3.translation(A3.origin(), p) + sage: T = phi * Tp.embedding_morphism() + sage: T.image() + Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: + -2*y + z + 1, + x + y + z + sage: _ == C.tangent_line(p) + True + + """ + A = self.ambient_space() + R = A.coordinate_ring() + gens = R.gens() + + Tp = self.tangent_space(p) + + if Tp.dimension() > 1: + raise ValueError("the curve is not smooth at {}".format(p)) + + from sage.schemes.curves.all import Curve + + # translate to p + I = [] + for poly in Tp.defining_polynomials(): + I.append(poly.subs(dict([x, x - c] for x, c in zip(gens, list(p))))) + + return Curve(I) + class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field): """ diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 592bb68dc65..37db99c4e37 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -122,6 +122,7 @@ QQbar) from sage.rings.rational_field import is_RationalField from sage.rings.integer import Integer + from sage.schemes.projective.projective_space import ProjectiveSpace, is_ProjectiveSpace from sage.schemes.projective.projective_subscheme import (AlgebraicScheme_subscheme_projective, @@ -1558,6 +1559,33 @@ def is_complete_intersection(self): L = singular.is_ci(I).sage() return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1] + def tangent_line(self, p): + """ + Return the tangent line at the point ``p``. + + INPUT: + + - ``p`` -- a rational point of the curve + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) + sage: p = C(1,1,1,1) + sage: C.tangent_line(p) + Projective Curve over Rational Field defined by -2*x + y + w, -3*x + z + 2*w + + """ + for i in range(len(p)): + if p[i]: + break + + C = self.affine_patch(i) + q = p.dehomogenize(i) + T = C.tangent_line(q) + + return T.projective_closure(i, self.ambient_space()) + class ProjectivePlaneCurve_field(ProjectivePlaneCurve, ProjectiveCurve_field): """ diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 2a2916ef49c..4fed0413bac 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1679,7 +1679,7 @@ def curve(self,F): INPUT: - ``F`` -- a polynomial, or a list or tuple of polynomials in - the coordinate ring of this projective space. + the coordinate ring of this projective space EXAMPLES:: @@ -1690,6 +1690,37 @@ def curve(self,F): from sage.schemes.curves.constructor import Curve return Curve(F, self) + def line_through(self, p, q): + """ + Return the line through ``p`` and ``q``. + + INPUT: + + - ``p``, ``q`` -- distinct rational points of the projective space + + EXAMPLES:: + + sage: P3. = ProjectiveSpace(3, QQ) + sage: p1 = P3(1, 2, 3, 4) + sage: p2 = P3(4, 3, 2, 1) + sage: P3.line_through(p1, p2) + Projective Curve over Rational Field defined by -5/4*x0 + 5/2*x1 - 5/4*x2, + -5/2*x0 + 15/4*x1 - 5/4*x3, -5/4*x0 + 15/4*x2 - 5/2*x3, -5/4*x1 + 5/2*x2 - 5/4*x3 + sage: p3 = P3(2,4,6,8) + sage: P3.line_through(p1, p3) + Traceback (most recent call last): + ... + ValueError: not distinct points + + """ + if p == q: + raise ValueError("not distinct points") + + from sage.schemes.curves.constructor import Curve + + m = matrix(3, list(self.gens()) + list(p) + list(q)) + return Curve([f for f in m.minors(3) if f]) + class ProjectiveSpace_finite_field(ProjectiveSpace_field): def _point(self, *args, **kwds): From bcb56ac4e1e1a9e9ac283f5ee82d3519f22d439d Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 1 Jun 2020 10:47:01 +0900 Subject: [PATCH 351/476] A bug fix --- src/sage/schemes/curves/affine_curve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 9e511f44514..af0789e1d33 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1656,7 +1656,7 @@ def tangent_line(self, p): for poly in Tp.defining_polynomials(): I.append(poly.subs(dict([x, x - c] for x, c in zip(gens, list(p))))) - return Curve(I) + return Curve(I, A) class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field): From 86729adfd580b6008d7494934abc715feaa269cd Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 1 Jun 2020 15:22:54 +0900 Subject: [PATCH 352/476] Cleaning fixes suggested by the reviewer --- src/sage/schemes/affine/affine_space.py | 2 +- src/sage/schemes/affine/affine_subscheme.py | 2 +- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/projective_curve.py | 11 +++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 4e7c65a283e..b6c2f2d6989 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -970,7 +970,7 @@ def origin(self): True """ - return self([0 for i in range(self.ngens())]) + return self([0]*self.ngens()) class AffineSpace_field(AffineSpace_generic): diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index 1f7bc652234..f6a2171bfca 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -590,7 +590,7 @@ def tangent_space(self, p): gens = R.gens() J = self.Jacobian_matrix() - Jp = J.apply_map( lambda f: f.subs(dict(zip(gens, list(p)))) ) + Jp = J.apply_map( lambda f: f.subs(dict(zip(gens, p))) ) I = [f for f in Jp * vector(gens) if f] return A.subscheme(R.ideal(I)) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index af0789e1d33..a0bb92c7b59 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1654,7 +1654,7 @@ def tangent_line(self, p): # translate to p I = [] for poly in Tp.defining_polynomials(): - I.append(poly.subs(dict([x, x - c] for x, c in zip(gens, list(p))))) + I.append(poly.subs({x: x - c for x, c in zip(gens, p)})) return Curve(I, A) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 37db99c4e37..a7bfdd7c943 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1578,13 +1578,12 @@ def tangent_line(self, p): """ for i in range(len(p)): if p[i]: - break - - C = self.affine_patch(i) - q = p.dehomogenize(i) - T = C.tangent_line(q) + C = self.affine_patch(i) + q = p.dehomogenize(i) + T = C.tangent_line(q) + return T.projective_closure(i, self.ambient_space()) - return T.projective_closure(i, self.ambient_space()) + raise TypeError("{} does not define a point in the projective space".format(p)) class ProjectivePlaneCurve_field(ProjectivePlaneCurve, ProjectiveCurve_field): From 8d84c436878cb61c19db470c23711d1c6804de37 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 1 Jun 2020 08:58:06 +0200 Subject: [PATCH 353/476] Remove a few future imports These are obsolete with Python 3.7. See https://docs.python.org/3/reference/simple_stmts.html#future-statements --- src/sage/all.py | 9 ++------- src/sage/manifolds/manifold.py | 2 -- src/sage/tensor/all.py | 1 - src/sage/tensor/differential_form_element.py | 2 -- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/sage/all.py b/src/sage/all.py index 94337b48d5f..9425219b7c1 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -57,12 +57,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -# Future statements which apply to this module. We delete the -# future globals because we do not want these to appear in the sage.all -# namespace. This deleting does not affect the parsing of this module. -from __future__ import absolute_import, division, print_function -del absolute_import, division, print_function - import os import sys import operator @@ -79,7 +73,8 @@ warnings.filterwarnings('ignore', category=ImportWarning) warnings.filterwarnings('ignore', category=ResourceWarning) else: - warnings.filters.remove(('ignore', None, DeprecationWarning, None, 0)) + deprecationWarning = ('ignore', None, DeprecationWarning, None, 0) + if deprecationWarning in warnings.filters: warnings.filters.remove(deprecationWarning) # The psutil swap_memory() function tries to collect some statistics # that may not be available and that we don't need. Hide the warnings diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 942e8d58cd8..68668fb9a46 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -324,8 +324,6 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import from sage.categories.fields import Fields from sage.categories.manifolds import Manifolds diff --git a/src/sage/tensor/all.py b/src/sage/tensor/all.py index cb7b9845b0c..b85a40c1b9d 100644 --- a/src/sage/tensor/all.py +++ b/src/sage/tensor/all.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from .coordinate_patch import CoordinatePatch from .differential_forms import DifferentialForms from .differential_form_element import DifferentialForm, wedge diff --git a/src/sage/tensor/differential_form_element.py b/src/sage/tensor/differential_form_element.py index 6721da31c57..8971514bbbe 100644 --- a/src/sage/tensor/differential_form_element.py +++ b/src/sage/tensor/differential_form_element.py @@ -21,8 +21,6 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import print_function - from sage.symbolic.ring import SR from sage.structure.element import RingElement, AlgebraElement From ea00610ae9d4b99c4e81b6b5a76fcb1f246726ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Jun 2020 10:30:17 +0200 Subject: [PATCH 354/476] fix syntax error, oups --- src/sage/combinat/finite_state_machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 48c928cb284..369f8abf039 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -4934,7 +4934,7 @@ def key_function(s): )) for ((source, target), transitions) in adjacent.items(): - if transitions): + if transitions: labels = [] for transition in transitions: if hasattr(transition, "format_label"): From 791bb94dc489931990c2875cdb413788c3009143 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Mon, 1 Jun 2020 11:04:24 +0200 Subject: [PATCH 355/476] Ignore jedi deprecation warnings --- src/sage/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/all.py b/src/sage/all.py index 94337b48d5f..88682c1ce38 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -91,7 +91,7 @@ # Ignore all deprecations from IPython etc. warnings.filterwarnings('ignore', category=DeprecationWarning, - module='.*(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic)') + module='.*(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') # Ignore collections.abc warnings, there are a lot of them but they are # harmless. warnings.filterwarnings('ignore', category=DeprecationWarning, From 0bba07c056ba7e1eb2cee0bbc763cc1e7041b933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Jun 2020 13:17:20 +0200 Subject: [PATCH 356/476] one detail in sparse matrices --- src/sage/matrix/matrix_rational_sparse.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 15476b9f48d..e4c6ac85f6c 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -179,6 +179,8 @@ cdef class Matrix_rational_sparse(Matrix_sparse): mpq_init(s) for i from 0 <= i < self._nrows: v = &self._matrix[i] + if not v.num_nonzero: + continue for j from 0 <= j < right._ncols: mpq_set_si(s, 0, 1) c = nonzero_positions_in_columns[j] 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 357/476] 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 358/476] 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 787e2bc6fdc950cdec225fc3a9fc7908badcdc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Jun 2020 15:51:49 +0200 Subject: [PATCH 359/476] more details in product of sparse matrices over QQ --- src/sage/matrix/matrix_rational_sparse.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index e4c6ac85f6c..306433431b8 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -165,10 +165,14 @@ cdef class Matrix_rational_sparse(Matrix_sparse): # Build a table that gives the nonzero positions in each column of right nonzero_positions_in_columns = [set([]) for _ in range(right._ncols)] cdef Py_ssize_t i, j, k - for i from 0 <= i < right._nrows: + for i in range(right._nrows): v = &(right._matrix[i]) - for j from 0 <= j < right._matrix[i].num_nonzero: + for j in range(right._matrix[i].num_nonzero): nonzero_positions_in_columns[v.positions[j]].add(i) + # prec-computes the list of nonzero columns of right + cdef list right_indices + right_indices = [j for j in range(right._ncols) + if nonzero_positions_in_columns[j]] ans = self.new_matrix(self._nrows, right._ncols) @@ -177,11 +181,11 @@ cdef class Matrix_rational_sparse(Matrix_sparse): mpq_init(x) mpq_init(y) mpq_init(s) - for i from 0 <= i < self._nrows: + for i in range(self._nrows): v = &self._matrix[i] if not v.num_nonzero: continue - for j from 0 <= j < right._ncols: + for j in right_indices: mpq_set_si(s, 0, 1) c = nonzero_positions_in_columns[j] for k from 0 <= k < v.num_nonzero: From 453dcc5dec5c539595cab5352521d2b065c8635a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 1 Jun 2020 16:21:23 +0200 Subject: [PATCH 360/476] 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 361/476] 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 362/476] 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 23cf6e7e04153d43d8504495dda46064f722bc84 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 1 Jun 2020 15:13:57 +0200 Subject: [PATCH 363/476] 29776: fix tab-completion for morphism methods --- src/sage/cpython/getattr.pyx | 11 ++++++++--- src/sage/structure/element.pyx | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/sage/cpython/getattr.pyx b/src/sage/cpython/getattr.pyx index 0e4f9a49698..94d1d7fabfb 100644 --- a/src/sage/cpython/getattr.pyx +++ b/src/sage/cpython/getattr.pyx @@ -411,7 +411,7 @@ cpdef getattr_from_other_class(self, cls, name): raise AttributeError(dummy_error_message) -def dir_with_other_class(self, cls): +def dir_with_other_class(self, *cls): r""" Emulates ``dir(self)``, as if self was also an instance ``cls``, right after ``caller_class`` in the method resolution order @@ -432,6 +432,10 @@ def dir_with_other_class(self, cls): sage: from sage.cpython.getattr import dir_with_other_class sage: dir_with_other_class(x, B) [..., 'a', 'b', 'c', 'd', 'e'] + sage: class C(object): + ....: f = 6 + sage: dir_with_other_class(x, B, C) + [..., 'a', 'b', 'c', 'd', 'e', 'f'] Check that objects without dicts are well handled:: @@ -459,6 +463,7 @@ def dir_with_other_class(self, cls): ret.update(dir(self.__class__)) if hasattr(self, "__dict__"): ret.update(list(self.__dict__)) - if not isinstance(self, cls): - ret.update(dir(cls)) + for c in cls: + if not isinstance(self, c): + ret.update(dir(c)) return sorted(ret) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index a5fbd555f2d..0791c72a70c 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -501,9 +501,12 @@ cdef class Element(SageObject): def __dir__(self): """ + Emulate ``__dir__`` for elements with dynamically attached methods. + Let cat be the category of the parent of ``self``. This method emulates ``self`` being an instance of both ``Element`` and - ``cat.element_class``, in that order, for attribute directory. + ``cat.element_class`` (and the corresponding ``morphism_class`` in the + case of a morphism), in that order, for attribute directory. EXAMPLES:: @@ -516,9 +519,26 @@ cdef class Element(SageObject): [..., 'is_idempotent', 'is_integer', 'is_integral', ...] sage: dir(1) # todo: not implemented [..., 'is_idempotent', 'is_integer', 'is_integral', ...] + + TESTS: + + Check that morphism classes are handled correctly (:trac:`29776`):: + + sage: R. = QQ[] + sage: f = R.hom([x, y+1], R) + sage: 'cartesian_product' in dir(f) + True + sage: 'extend_to_fraction_field' in dir(f) + True """ from sage.cpython.getattr import dir_with_other_class - return dir_with_other_class(self, self.parent().category().element_class) + ec = self.parent().category().element_class + try: + mc = self.category_for().morphism_class + except AttributeError: + return dir_with_other_class(self, ec) + else: + return dir_with_other_class(self, ec, mc) def _repr_(self): return "Generic element of a structure" From ad0dc039713e3664b89f198ae96d508697652dd6 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 22 May 2020 20:00:42 +0200 Subject: [PATCH 364/476] 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 365/476] 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 366/476] 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 eac7eca8ffd825e248c50eb7c9a69a723d47642c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 1 Jun 2020 14:59:28 -0700 Subject: [PATCH 367/476] Fixup --- .github/workflows/tox-gcc_spkg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tox-gcc_spkg.yml b/.github/workflows/tox-gcc_spkg.yml index 7b66b586314..f9a9847f9a9 100644 --- a/.github/workflows/tox-gcc_spkg.yml +++ b/.github/workflows/tox-gcc_spkg.yml @@ -101,7 +101,7 @@ jobs: fail-fast: false matrix: tox_system_factor: [conda-forge-ubuntu] - tox_packages_factor: [minimal-gcc_spkg, standard-gcc_spkg, standard] + tox_packages_factor: [minimal-gcc_spkg, standard-gcc_spkg] env: TOX_ENV: local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} From 5867c054f9605ecb740120ef9e22d5e3c9b6a5e2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 1 Jun 2020 16:57:12 -0700 Subject: [PATCH 368/476] 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 369/476] 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 370/476] 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 371/476] 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 372/476] 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 170231f673dea3ccf65dd3ee486571f2c663e906 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 14:11:11 +1000 Subject: [PATCH 373/476] Some additional changes to rational sparse matrix mult. --- src/sage/matrix/matrix_rational_sparse.pyx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 306433431b8..aa532514023 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -163,13 +163,13 @@ cdef class Matrix_rational_sparse(Matrix_sparse): cdef mpq_vector* v # Build a table that gives the nonzero positions in each column of right - nonzero_positions_in_columns = [set([]) for _ in range(right._ncols)] + cdef list nonzero_positions_in_columns = [set() for _ in range(right._ncols)] cdef Py_ssize_t i, j, k for i in range(right._nrows): v = &(right._matrix[i]) - for j in range(right._matrix[i].num_nonzero): - nonzero_positions_in_columns[v.positions[j]].add(i) - # prec-computes the list of nonzero columns of right + for j in range(v.num_nonzero): + ( nonzero_positions_in_columns[v.positions[j]]).add(i) + # pre-computes the list of nonzero columns of right cdef list right_indices right_indices = [j for j in range(right._ncols) if nonzero_positions_in_columns[j]] @@ -177,18 +177,19 @@ cdef class Matrix_rational_sparse(Matrix_sparse): ans = self.new_matrix(self._nrows, right._ncols) # Now do the multiplication, getting each row completely before filling it in. + cdef set c cdef mpq_t x, y, s mpq_init(x) mpq_init(y) mpq_init(s) for i in range(self._nrows): - v = &self._matrix[i] + v = &(self._matrix[i]) if not v.num_nonzero: continue for j in right_indices: mpq_set_si(s, 0, 1) - c = nonzero_positions_in_columns[j] - for k from 0 <= k < v.num_nonzero: + c = nonzero_positions_in_columns[j] + for k in range(v.num_nonzero): if v.positions[k] in c: mpq_vector_get_entry(y, &right._matrix[v.positions[k]], j) mpq_mul(x, v.entries[k], y) From c146ac073e16a0d651b2041ce69491dd7741f4b5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 14:11:34 +1000 Subject: [PATCH 374/476] Making similar changes to matrix_modn_sparse.pyx. --- src/sage/matrix/matrix_modn_sparse.pyx | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 1d0f8e94c32..335be5fb687 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -271,7 +271,8 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): Even though sparse and dense matrices are represented differently, they still compare as equal if they have the - same entries: + same entries:: + sage: a*b == a._matrix_times_matrix_dense(b) True sage: d = matrix(GF(43), 3, 8, range(24)) @@ -287,7 +288,6 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): [32770 32770 32770] sage: M*M.transpose() # previously returned [32738] [3] - """ cdef Matrix_modn_sparse right, ans right = _right @@ -295,24 +295,29 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): cdef c_vector_modint* v # Build a table that gives the nonzero positions in each column of right - nonzero_positions_in_columns = [set([]) for _ in range(right._ncols)] + cdef list nonzero_positions_in_columns = [set() for _ in range(right._ncols)] cdef Py_ssize_t i, j, k - for i from 0 <= i < right._nrows: + for i in range(right._nrows): v = &(right.rows[i]) - for j from 0 <= j < right.rows[i].num_nonzero: - nonzero_positions_in_columns[v.positions[j]].add(i) + for j in range(v.num_nonzero): + ( nonzero_positions_in_columns[v.positions[j]]).add(i) + # pre-computes the list of nonzero columns of right + cdef list right_indices + right_indices = [j for j in range(right._ncols) + if nonzero_positions_in_columns[j]] ans = self.new_matrix(self._nrows, right._ncols) # Now do the multiplication, getting each row completely before filling it in. cdef int x, y, s + cdef set c - for i from 0 <= i < self._nrows: - v = &self.rows[i] - for j from 0 <= j < right._ncols: + for i in range(self._nrows): + v = &(self.rows[i]) + for j in range(right._ncols): s = 0 - c = nonzero_positions_in_columns[j] - for k from 0 <= k < v.num_nonzero: + c = nonzero_positions_in_columns[j] + for k in range(v.num_nonzero): if v.positions[k] in c: y = get_entry(&right.rows[v.positions[k]], j) x = v.entries[k] * y From e396cefbb5df32902ad136fb651f9a8390eecccf Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 14:11:53 +1000 Subject: [PATCH 375/476] Adding custom _matrix_times_matrix_ for sparse ZZ matrices. --- src/sage/matrix/matrix_integer_sparse.pyx | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index c6cb12ad86a..8163172d862 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -219,6 +219,63 @@ cdef class Matrix_integer_sparse(Matrix_sparse): self.cache('dict', d) return d + cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix _right): + """ + Return the product of the sparse integer matrices + ``self`` and ``_right``. + + EXAMPLES:: + + sage: a = matrix(ZZ, 2, [1,2,3,4], sparse=True) + sage: b = matrix(ZZ, 2, 3, [1..6], sparse=True) + sage: a * b + [ 9 12 15] + [19 26 33] + """ + cdef Matrix_integer_sparse right, ans + right = _right + + cdef mpz_vector* v + + # Build a table that gives the nonzero positions in each column of right + cdef list nonzero_positions_in_columns = [set() for _ in range(right._ncols)] + cdef Py_ssize_t i, j, k + for i in range(right._nrows): + v = &(right._matrix[i]) + for j in range(v.num_nonzero): + ( nonzero_positions_in_columns[v.positions[j]]).add(i) + # pre-computes the list of nonzero columns of right + cdef list right_indices + right_indices = [j for j in range(right._ncols) + if nonzero_positions_in_columns[j]] + + ans = self.new_matrix(self._nrows, right._ncols) + + # Now do the multiplication, getting each row completely before filling it in. + cdef set c + cdef mpz_t x, y, s + mpz_init(x) + mpz_init(y) + mpz_init(s) + for i in range(self._nrows): + v = &(self._matrix[i]) + if not v.num_nonzero: + continue + for j in right_indices: + mpz_set_si(s, 0) + c = nonzero_positions_in_columns[j] + for k in range(v.num_nonzero): + if v.positions[k] in c: + mpz_vector_get_entry(y, &right._matrix[v.positions[k]], j) + mpz_mul(x, v.entries[k], y) + mpz_add(s, s, x) + mpz_vector_set_entry(&ans._matrix[i], j, s) + + mpz_clear(x) + mpz_clear(y) + mpz_clear(s) + return ans + ######################################################################## # LEVEL 3 functionality (Optional) # * cdef _sub_ From 0e6d768dc9b415facc07d9458545fa6900f7adce Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 14:13:10 +1000 Subject: [PATCH 376/476] Making generic sparse tests actually test generic sparse matrices. --- src/sage/matrix/matrix_generic_sparse.pyx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index bbf0015ca8a..7618257e13a 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -210,7 +210,8 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): """ EXAMPLES:: - sage: a = matrix([[1,10],[3,4]],sparse=True); a + sage: R. = ZZ[] + sage: a = matrix(R, [[1,10],[3,4]],sparse=True); a [ 1 10] [ 3 4] sage: loads(dumps(a)) == a @@ -239,7 +240,8 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): """ EXAMPLES:: - sage: a = matrix([[1,10],[3,4]],sparse=True); a + sage: R. = QQ[] + sage: a = matrix(R, [[1,10],[3,4]],sparse=True); a [ 1 10] [ 3 4] sage: a+a @@ -248,7 +250,7 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): :: - sage: a = matrix([[1,10,-5/3],[2/8,3,4]],sparse=True); a + sage: a = matrix(R, [[1,10,-5/3],[2/8,3,4]], sparse=True); a [ 1 10 -5/3] [ 1/4 3 4] sage: a+a From a02a614ca3d98e4b9e76cf21d23a8efe96d78b98 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Tue, 2 Jun 2020 10:55:42 +0530 Subject: [PATCH 377/476] 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 2053489fe558b86aa5f6e7789afd0663b7045db0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 15:55:24 +1000 Subject: [PATCH 378/476] Microimprovements and cleanup of generic sparse multiplication. --- src/sage/matrix/matrix_sparse.pyx | 47 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index d5dca213251..80b1d979d74 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -177,17 +177,20 @@ cdef class Matrix_sparse(matrix.Matrix): sage: type(A) sage: B = matrix(QQ['x,y'], 2, [-1,-1,-2,-2], sparse=True) - sage: A*B + sage: A * B [2 2] [2 2] + sage: B * A + [-2 3] + [-4 6] """ cdef Py_ssize_t row, col, row_start, k1, k2, len_left, len_right, a, b - left_nonzero = left.nonzero_positions(copy=False, column_order=False) - right_nonzero = right.nonzero_positions(copy=False, column_order=True) + cdef list left_nonzero = left.nonzero_positions(copy=False, column_order=False) + cdef list right_nonzero = right.nonzero_positions(copy=False, column_order=True) len_left = len(left_nonzero) len_right = len(right_nonzero) - e = {} + cdef dict e = {} k1 = 0 while k1 < len_left: row_start = k1 @@ -196,30 +199,30 @@ cdef class Matrix_sparse(matrix.Matrix): while k2 < len_right: sig_check() col = get_ij(right_nonzero, k2, 1) - sum = None + s = None k1 = row_start - while k1 < len_left and get_ij(left_nonzero,k1,0) == row and \ - k2 < len_right and get_ij(right_nonzero,k2,1) == col: + while (k1 < len_left and get_ij(left_nonzero,k1,0) == row + and k2 < len_right and get_ij(right_nonzero,k2,1) == col): sig_check() - a = get_ij(left_nonzero, k1,1) - b = get_ij(right_nonzero,k2,0) + a = get_ij(left_nonzero, k1, 1) + b = get_ij(right_nonzero, k2, 0) if a == b: - if sum is None: - sum = left.get_unsafe(row,a)*right.get_unsafe(a,col) + if s is None: + s = left.get_unsafe(row,a) * right.get_unsafe(a,col) else: - sum = sum + left.get_unsafe(row,a)*right.get_unsafe(a,col) - k1 = k1 + 1 - k2 = k2 + 1 + s += left.get_unsafe(row,a) * right.get_unsafe(a,col) + k1 += 1 + k2 += 1 elif a < b: - k1 = k1 + 1 + k1 += 1 else: - k2 = k2 + 1 - if sum is not None: - e[row, col] = sum - while k2 < len_right and get_ij(right_nonzero,k2,1) == col: - k2 = k2 + 1 - while k1 < len_left and get_ij(left_nonzero,k1,0) == row: - k1 = k1 + 1 + k2 += 1 + if s is not None: + e[row, col] = s + while k2 < len_right and get_ij(right_nonzero, k2, 1) == col: + k2 += 1 + while k1 < len_left and get_ij(left_nonzero, k1, 0) == row: + k1 += 1 return left.new_matrix(left._nrows, right._ncols, entries=e, coerce=False, copy=False) def _multiply_classical_with_cache(Matrix_sparse left, Matrix_sparse right): From d9c90d1dbe213ce1711f5f2b2aef68cf313f60ba Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 2 Jun 2020 09:15:22 +0200 Subject: [PATCH 379/476] 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 380/476] 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 746982bdc67e6c4a9b37a08fe756b02e3ddabe36 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 2 Jun 2020 11:36:12 +0100 Subject: [PATCH 381/476] properly catch exceptions in Dijkstra_Boost recent versions of Boost (1.73) throw an exception on encountering a negative edge weight. It needs to be properly caught with try/except. --- src/sage/graphs/base/boost_graph.pyx | 29 +++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 6ba0a44c9af..216688c733b 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -977,19 +977,22 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): raise ValueError("the graph contains a negative cycle") elif algorithm in ['Dijkstra', 'Dijkstra_Boost']: - if g.is_directed(): - boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) - vi = v_to_int[start] - sig_on() - result = g_boost_dir.dijkstra_shortest_paths(vi) - sig_off() - else: - boost_weighted_graph_from_sage_graph(&g_boost_und, g, v_to_int, weight_function) - vi = v_to_int[start] - sig_on() - result = g_boost_und.dijkstra_shortest_paths(vi) - sig_off() - if not result.distances.size(): + try: + if g.is_directed(): + boost_weighted_graph_from_sage_graph(&g_boost_dir, g, v_to_int, weight_function) + vi = v_to_int[start] + sig_on() + result = g_boost_dir.dijkstra_shortest_paths(vi) + sig_off() + else: + boost_weighted_graph_from_sage_graph(&g_boost_und, g, v_to_int, weight_function) + vi = v_to_int[start] + sig_on() + result = g_boost_und.dijkstra_shortest_paths(vi) + sig_off() + if not result.distances.size(): + raise RuntimeError("Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead") + except RuntimeError: raise RuntimeError("Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead") else: From a44162166f72f1a74aef86b04cac7aa99fd2e5c2 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Tue, 2 Jun 2020 04:43:21 -0700 Subject: [PATCH 382/476] 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 383/476] 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 384/476] 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 385/476] 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 386/476] 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 8061aa2073e806dc3c465c4a53828604d5b1802d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 3 Jun 2020 16:01:57 +1000 Subject: [PATCH 387/476] Fixing the pdf docbuild. --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/algebraic_combinatorics.py | 1 + src/sage/docs/conf.py | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 64e844e9b8a..47dbe0fb281 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -25,6 +25,7 @@ Comprehensive Module list sage/combinat/baxter_permutations sage/combinat/binary_recurrence_sequences sage/combinat/binary_tree + sage/combinat/blob_algebra sage/combinat/cartesian_product sage/combinat/catalog_partitions sage/combinat/chas/__init__ diff --git a/src/sage/combinat/algebraic_combinatorics.py b/src/sage/combinat/algebraic_combinatorics.py index f0ff485a5a2..599913ffdb8 100644 --- a/src/sage/combinat/algebraic_combinatorics.py +++ b/src/sage/combinat/algebraic_combinatorics.py @@ -36,6 +36,7 @@ - :class:`~sage.algebras.affine_nil_temperley_lieb.AffineNilTemperleyLiebTypeA` - :ref:`sage.combinat.descent_algebra` - :ref:`sage.combinat.diagram_algebras` +- :ref:`sage.combinat.blob_algebra` Combinatorial Representation Theory ----------------------------------- diff --git a/src/sage/docs/conf.py b/src/sage/docs/conf.py index a5c8d96acdf..7a4c0002050 100644 --- a/src/sage/docs/conf.py +++ b/src/sage/docs/conf.py @@ -455,6 +455,13 @@ def set_intersphinx_mappings(app): \DeclareUnicodeCharacter{23AE}{\ensuremath{\|}} % integral extenison \DeclareUnicodeCharacter{2571}{/} % Box drawings light diagonal upper right to lower left + + \DeclareUnicodeCharacter{25CF}{\ensuremath{\bullet}} % medium black circle + \DeclareUnicodeCharacter{26AC}{\ensuremath{\circ}} % medium small white circle + \DeclareUnicodeCharacter{256D}{+} + \DeclareUnicodeCharacter{256E}{+} + \DeclareUnicodeCharacter{256F}{+} + \DeclareUnicodeCharacter{2570}{+} \fi \let\textLaTeX\LaTeX From bfd9fedc42fe0b770edf87cf56e488a21e6099ca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 2 Jun 2020 23:15:14 -0700 Subject: [PATCH 388/476] 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 389/476] 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 390/476] 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 391/476] 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 392/476] 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 393/476] 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 394/476] 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 395/476] 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 396/476] 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 397/476] 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 398/476] 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 399/476] 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 400/476] 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 401/476] 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 402/476] 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 403/476] 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 404/476] 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 405/476] 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 406/476] 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 407/476] 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 408/476] 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 409/476] 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 410/476] 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 411/476] 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 412/476] 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 413/476] 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 414/476] 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 415/476] 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 416/476] 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 c3fe0daadc5e65efd7647fb4f81e7eac4862f6f3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Jun 2020 13:23:17 +1000 Subject: [PATCH 417/476] Some mild PEP8 stuff and other formatting stuff for splitting algebras. --- src/sage/algebras/splitting_algebra.py | 284 ++++++++++++------------- 1 file changed, 131 insertions(+), 153 deletions(-) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 676fc54615d..024851ea00e 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -2,23 +2,28 @@ r""" Splitting Algebras -*Splitting algebras* have been considered by Dan Laksov, Anders Thorup, Torsten Ekedahl and others (see references below) in order -to study intersection theory of Grassmann and other flag schemes. Similarily as *splitting fields* they can be considered as -extensions of rings containing all the roots of a given monic polynomial over that ring under the assumption that its Galois -group is the symmetric group of order equal to the polynomial's degree. - -Thus they can be used as a tool to express elements of a ring generated by `n` indeterminates in terms of symmetric functions -in these indeterminates. - -This realization of splitting algebras follows the approach of a recursive quotient ring construction splitting off some linear -factor of the polynomial in each recursive step. Accordingly it is inherited from :class:`PolynomialQuotientRing_domain`. +*Splitting algebras* have been considered by Dan Laksov, Anders Thorup, +Torsten Ekedahl and others (see references below) in order to study +intersection theory of Grassmann and other flag schemes. Similarily as +*splitting fields* they can be considered as extensions of rings containing +all the roots of a given monic polynomial over that ring under the +assumption that its Galois group is the symmetric group of order equal +to the polynomial's degree. + +Thus they can be used as a tool to express elements of a ring generated by +`n` indeterminates in terms of symmetric functions in these indeterminates. + +This realization of splitting algebras follows the approach of a recursive +quotient ring construction splitting off some linear factor of the +polynomial in each recursive step. Accordingly it is inherited from +:class:`PolynomialQuotientRing_domain`. AUTHORS: -- Sebastian Oehms April 2020: initial version +- Sebastian Oehms (April 2020): initial version """ -############################################################################## +# **************************************************************************** # Copyright (C) 2020 Sebastian Oehms # # This program is free software: you can redistribute it and/or modify @@ -26,13 +31,8 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -############################################################################## - - - +# **************************************************************************** -#################################################################################################### -#################################################################################################### from warnings import warn @@ -42,19 +42,16 @@ from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement - - # ------------------------------------------------------------------------------------------------------------------ # Element class for the splitting algebra # -------------------------------------------------------------------------------------------------------- class SplittingAlgebraElement(PolynomialQuotientRingElement): r""" - Element class for :class:`SplittingAlgebra` + Element class for :class:`SplittingAlgebra`. EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: from sage.misc.functional import cyclotomic_polynomial sage: cp6 = cyclotomic_polynomial(6) sage: CR6. = SplittingAlgebra(cp6) sage: type(e6) @@ -63,17 +60,17 @@ class SplittingAlgebraElement(PolynomialQuotientRingElement): sage: type(CR6(5)) """ - def __invert__(self): r""" - overloads inherited method in order to support inversion of special elements attached - to the construction of the parent and which are recorded in the list + Return the inverse of ``self``. + + Support inversion of special elements attached to the construction + of the parent and which are recorded in the list ``self.parent()._invertible_elements``. EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: from sage.misc.functional import cyclotomic_polynomial sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) sage: ~e3 -e3 - 1 @@ -83,7 +80,7 @@ def __invert__(self): NotImplementedError: The base ring (=Integer Ring) is not a field """ inv_elements = self.parent()._invertible_elements - if self in inv_elements.keys(): + if self in inv_elements: return inv_elements[self] return super(SplittingAlgebraElement, self).__invert__() @@ -96,13 +93,12 @@ def is_unit(self): EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: from sage.misc.functional import cyclotomic_polynomial sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) sage: e3.is_unit() True """ inv_elements = self.parent()._invertible_elements - if self in inv_elements.keys(): + if self in inv_elements: return True return super(SplittingAlgebraElement, self).is_unit() @@ -114,7 +110,6 @@ def dict(self): EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: from sage.misc.functional import cyclotomic_polynomial sage: CR3. = SplittingAlgebra(cyclotomic_polynomial(3)) sage: (e3 + 42).dict() {0: 42, 1: 1} @@ -122,40 +117,40 @@ def dict(self): return self.lift().dict() - # ------------------------------------------------------------------------------------------------------------------ # Parent class of the splitting algebra # -------------------------------------------------------------------------------------------------------- class SplittingAlgebra(PolynomialQuotientRing_domain): r""" - For a given monic polynomial `p(t)` of degree `n` over a commutative ring `R`, the - splitting algebra is the universal `R`-algebra in which `p(t)` has `n` roots, or, - more precisely, over which `p(t)` factors, + For a given monic polynomial `p(t)` of degree `n` over a commutative + ring `R`, the splitting algebra is the universal `R`-algebra in which + `p(t)` has `n` roots, or, more precisely, over which `p(t)` factors, .. MATH:: - p(t) = (t - \xi_1 ) \cdots (t - \xi_n). + p(t) = (t - \xi_1) \cdots (t - \xi_n). - This class creates an algebra as extension over the base ring of a given polynomial - `p` such that `p` splits into linear factors over that extension. It is assumed - (and not checked in general) that the Galois group of `p` is the symmetric Group - `S(n)`. The construction is recursive (following [LT2012]_, 1.3). + This class creates an algebra as extension over the base ring of a + given polynomial `p` such that `p` splits into linear factors over + that extension. It is assumed (and not checked in general) that the + Galois group of `p` is the symmetric Group `S(n)`. The construction + is recursive (following [LT2012]_, 1.3). INPUT: - ``monic_polynomial`` -- the monic polynomial which should be split - - ``names`` -- names for the indeterminates to be adjoined to the base ring of - ``monic_polynomial`` - - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) - to suppress a warning which will be thrown whenever it cannot be checked that - the Galois group of ``monic_polynomial`` is maximal + - ``names`` -- names for the indeterminates to be adjoined to the + base ring of ``monic_polynomial`` + - ``warning`` -- (default: ``True``) can be used (by setting to ``False``) + to suppress a warning which will be thrown whenever it cannot be + checked that the Galois group of ``monic_polynomial`` is maximal EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra sage: Lc. = LaurentPolynomialRing(ZZ) sage: PabLc. = Lc[]; t = polygen(PabLc) - sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t -w) + sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t - w) doctest:...: UserWarning: Asuming x^3 - u*x^2 + v*x - w to have maximal Galois group! @@ -163,9 +158,9 @@ class SplittingAlgebra(PolynomialQuotientRing_domain): [x, y, -y - x + u] sage: all(t^3 -u*t^2 +v*t -w == 0 for t in roots) True - sage: ~x + sage: xi = ~x; xi ((-w^-1)*x)*y + (-w^-1)*x^2 + ((w^-1)*u)*x - sage: ~_ == x + sage: ~xi == x True sage: ~y (w^-1)*x^2 + ((-w^-1)*u)*x + (w^-1)*v @@ -198,7 +193,6 @@ class SplittingAlgebra(PolynomialQuotientRing_domain): - [Tho2011]_ - [LT2012]_ """ - Element = SplittingAlgebraElement def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): @@ -210,7 +204,7 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): sage: from sage.algebras.splitting_algebra import SplittingAlgebra sage: Lw. = LaurentPolynomialRing(ZZ) sage: PuvLw. = Lw[]; t = polygen(PuvLw) - sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t - w) + sage: S. = SplittingAlgebra(t^3 - u*t^2 + v*t - w, warning=False) sage: TestSuite(S).run() """ @@ -220,30 +214,30 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): base_ring = monic_polynomial.base_ring() if not monic_polynomial.is_monic(): - raise ValueError('Given polynomial must be monic') + raise ValueError("given polynomial must be monic") deg = monic_polynomial.degree() from sage.structure.category_object import normalize_names self._root_names = normalize_names(deg-1, names) root_names = list(self._root_names) - verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" %(base_ring, monic_polynomial, iterate, warning)) + verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" + % (base_ring, monic_polynomial, iterate, warning)) self._defining_polynomial = monic_polynomial - self._iterate = iterate + self._iterate = iterate try: - if base_ring.is_integral_domain() == False: - raise TypeError( "base_ring must be an integral domain" ) + if not base_ring.is_integral_domain(): + raise TypeError("base_ring must be an integral domain") except NotImplementedError: from sage.rings.ring import Ring - if isinstance(base_ring, Ring) == False: - raise TypeError( "base_ring must be an instance of ring" ) - if warning == True: - warn('Assuming %s to be an integral domain!' %(base_ring)) - + if not isinstance(base_ring, Ring): + raise TypeError("base_ring must be an instance of ring") + if warning: + warn('Assuming %s to be an integral domain!' % (base_ring)) if deg < 1: - raise ValueError( "the degree of the polynomial must positive" ) + raise ValueError("the degree of the polynomial must positive") self._splitting_roots = [] self._coefficients_list = [] @@ -256,30 +250,30 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): # taking next root_name # ------------------------------------------------------------------------------------ root_name = root_names[0] - p = monic_polynomial.change_variable_name(root_name) + p = monic_polynomial.change_variable_name(root_name) P = p.parent() self._set_modulus_irreducible_ = False try: - if p.is_irreducible() == False: - raise ValueError( "monic_polynomial must be irreducible" ) + if not p.is_irreducible(): + raise ValueError("monic_polynomial must be irreducible") except (NotImplementedError, AttributeError): # assuming this has been checked mathematically before self._set_modulus_irreducible_ = True - if warning == True: - warn('Asuming %s to have maximal Galois group!' %(monic_polynomial)) + if warning: + warn('Asuming %s to have maximal Galois group!' % (monic_polynomial)) warning = False # one warning must be enough - verbose("P %s defined:" %(P)) + verbose("P %s defined:" % (P)) - if deg > 2 and iterate: + if deg > 2 and iterate: # ------------------------------------------------------------------------------------ # successive solution via recursion (on base_ring_step) # ------------------------------------------------------------------------------------ base_ring_step = SplittingAlgebra(monic_polynomial, tuple(root_names), iterate=False, warning=False) first_root = base_ring_step.gen() - verbose("base_ring_step %s defined:" %(base_ring_step)) + verbose("base_ring_step %s defined:" % (base_ring_step)) # ------------------------------------------------------------------------------------ # splitting first root off @@ -292,14 +286,14 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): p = P(monic_polynomial.dict()) q, r = p.quo_rem( (P.gen()-first_root) ) - verbose("Invoking recursion with: %s" %(q)) + verbose("Invoking recursion with: %s" % (q,)) SplittingAlgebra.__init__(self, q, root_names_reduces, warning=False) splitting_roots = base_ring_step._splitting_roots + self._splitting_roots coefficients_list = base_ring_step._coefficients_list + self._coefficients_list - verbose("Adding roots: %s" %(splitting_roots)) + verbose("Adding roots: %s" % (splitting_roots)) self._splitting_roots = splitting_roots self._coefficients_list = coefficients_list @@ -310,20 +304,20 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): self._splitting_roots.append(first_root) self._coefficients_list = [monic_polynomial.coefficients(sparse=False)] - if iterate == False: - verbose("pre ring defined splitting_roots: %s" %(self._splitting_roots)) + if not iterate: + verbose("pre ring defined splitting_roots: %s" % (self._splitting_roots)) return - verbose("final ring defined splitting_roots: %s" %(self._splitting_roots)) + verbose("final ring defined splitting_roots: %s" % (self._splitting_roots)) if deg == 2: coefficients = monic_polynomial.coefficients(sparse=False) lin_coeff = coefficients[1] self._splitting_roots.append(-lin_coeff - first_root) - self._root_names = names + self._root_names = names self._splitting_roots = [self(root) for root in self._splitting_roots] - verbose("splitting_roots: %s embedded" %(self._splitting_roots)) + verbose("splitting_roots: %s embedded" % (self._splitting_roots)) # ------------------------------------------------------------------------------------------- @@ -350,23 +344,23 @@ def __init__(self, monic_polynomial, names='X', iterate=True, warning=True): # assuming that cf splits into linear factors over self and the _splitting_roots # are its roots we can calculate inverses # ---------------------------------------------------------------------------------- - if cf0_inv != None: + if cf0_inv is not None: deg_cf = len(cf)-1 pf = P(cf) for root in self._splitting_roots: - check=self(pf) + check = self(pf) if not check.is_zero(): continue root_inv = self.one() for pos in range(deg_cf-1 ): - root_inv = (-1 )**(pos+1 )*cf[deg_cf-pos-1 ] - root_inv*root - verbose("inverse %s of root %s" %(root_inv, root)) - root_inv = (-1 )**(deg_cf)*cf0_inv*root_inv + root_inv = (-1 )**(pos+1 ) * cf[deg_cf-pos-1 ] - root_inv * root + verbose("inverse %s of root %s" % (root_inv, root)) + root_inv = (-1 )**(deg_cf) * cf0_inv * root_inv self._invertible_elements.update({root:root_inv}) - verbose("adding inverse %s of root %s" %(root_inv, root)) + verbose("adding inverse %s of root %s" % (root_inv, root)) invert_items = [(k,v) for k, v in self._invertible_elements.items()] for k, v in invert_items: - self._invertible_elements.update({v:k}) + self._invertible_elements.update({v: k}) return @@ -383,7 +377,7 @@ def __reduce__(self): sage: from sage.algebras.splitting_algebra import SplittingAlgebra sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) - sage: S = SplittingAlgebra(x^4 -t*x^3 - u*x^2 - v*x + w, ('X', 'Y', 'Z')) + sage: S = SplittingAlgebra(x^4 -t*x^3 - u*x^2 - v*x + w, ('X', 'Y', 'Z'), warning=False) sage: S.__reduce__() (, (x^4 - t*x^3 - u*x^2 - v*x + w, ('X', 'Y', 'Z'), True, False)) @@ -394,9 +388,7 @@ def __reduce__(self): False, False)) - TESTS:: - - TestSuite(SplAlg).run() + sage: TestSuite(S).run() """ defining_polynomial = self.defining_polynomial() definig_coefficients = self._coefficients_list[0] @@ -414,7 +406,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: L. = PolynomialRing(ZZ) + sage: L. = PolynomialRing(ZZ) sage: t = polygen(L) sage: Spl. = SplittingAlgebra(t^3 - (u^2-v)*t^2 + (v+u)*t - 1) sage: Spl._repr_() @@ -423,12 +415,14 @@ def _repr_(self): over Multivariate Polynomial Ring in u, v over Integer Ring' sage: Spl.base_ring() # indirect doctest Factorization Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 - with roots [S] over Multivariate Polynomial Ring in u, v over Integer Ring + with roots [S] over Multivariate Polynomial Ring in u, v over Integer Ring """ if self.is_completely_split(): - return 'Splitting Algebra of %s with roots %s over %s' %(self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) + return ('Splitting Algebra of %s with roots %s over %s' + % (self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring())) else: - return 'Factorization Algebra of %s with roots %s over %s' %(self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) + return ('Factorization Algebra of %s with roots %s over %s' + % (self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring())) def _first_ngens(self, n): r""" @@ -437,12 +431,13 @@ def _first_ngens(self, n): EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: L. = PolynomialRing(ZZ) + sage: L. = PolynomialRing(ZZ) sage: t = polygen(L) sage: S. = SplittingAlgebra(t^3 - (u^2-v)*t^2 + (v+u)*t - 1) # indirect doctest sage: X.parent() - Splitting Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 with roots [X, Y, -Y - X + u^2 - v] - over Multivariate Polynomial Ring in u, v over Integer Ring + Splitting Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 + with roots [X, Y, -Y - X + u^2 - v] + over Multivariate Polynomial Ring in u, v over Integer Ring """ return self.gens_recursive()[:n] @@ -453,8 +448,12 @@ def _element_constructor_(self, x): TESTS:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) sage: S. = SplittingAlgebra(x^3 - u*x^2 + v*x - w) + sage: S(u + v) + u + v + sage: S(X*Y + X) + (X + 1)*Y sage: TestSuite(S).run() # indirect doctest """ if isinstance(x, SplittingAlgebraElement): @@ -462,8 +461,6 @@ def _element_constructor_(self, x): return self(x.lift()) return super(SplittingAlgebra, self)._element_constructor_(x) - - def hom(self, im_gens, codomain=None, check=True, base_map=None): r""" This version keeps track with the special recursive structure @@ -475,9 +472,9 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): EXAMPLES:: sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) + sage: L. = LaurentPolynomialRing(ZZ); x = polygen(L) sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) - sage: P. = PolynomialRing(ZZ) + sage: P. = PolynomialRing(ZZ) sage: F = FractionField(P) sage: im_gens = [F(g) for g in [y, x, x + y + z, x*y+x*z+y*z, x*y*z]] sage: f = S.hom(im_gens) @@ -488,7 +485,6 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): sage: [f(r) for r in roots] [x, y, z] """ - base_ring = self.base_ring() if not isinstance(im_gens, (list,tuple)): @@ -502,12 +498,12 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): im_gens_start = [img for img in im_gens if im_gens.index(img) < num_gens] im_gens_end = [img for img in im_gens if im_gens.index(img) >= num_gens] - if len(im_gens_end) == 0: + if not im_gens_end: return super(SplittingAlgebra, self).hom(im_gens, codomain=codomain, check=check, base_map=base_map) - verbose('base %s im_gens_end %s codomain %s check %s base_map %s' %(base_ring, im_gens_end, codomain, check, base_map)) + verbose('base %s im_gens_end %s codomain %s check %s base_map %s' % (base_ring, im_gens_end, codomain, check, base_map)) hom_on_base_recurs = base_ring.hom(im_gens_end, codomain=codomain, check=check, base_map=base_map) - verbose('hom_on_base_recurs %s' %(hom_on_base_recurs)) + verbose('hom_on_base_recurs %s' % (hom_on_base_recurs)) cover_ring = self.cover_ring() hom_from_cover = cover_ring.hom(im_gens_start, codomain=codomain, check=check, base_map=hom_on_base_recurs) @@ -543,9 +539,7 @@ def is_completely_split(self): sage: S.base_ring().is_completely_split() False """ - if len(self.splitting_roots()) < self.defining_polynomial().degree(): - return False - return True + return len(self.splitting_roots()) >= self.defining_polynomial().degree() @cached_method def lifting_map(self): @@ -580,7 +574,6 @@ def splitting_roots(self): sage: S.splitting_roots() [I, -I] """ - return self._splitting_roots @cached_method @@ -603,7 +596,6 @@ def gens_recursive(self): return res + base_ring.gens_recursive() return res + base_ring.gens() - @cached_method def scalar_base_ring(self): r""" @@ -617,7 +609,7 @@ def scalar_base_ring(self): sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) sage: S.base_ring() Factorization Algebra of x^3 - u*x^2 + v*x - w with roots [X] - over Multivariate Laurent Polynomial Ring in u, v, w over Integer Ring + over Multivariate Laurent Polynomial Ring in u, v, w over Integer Ring sage: S.scalar_base_ring() Multivariate Laurent Polynomial Ring in u, v, w over Integer Ring """ @@ -654,20 +646,6 @@ def defining_polynomial(self): return self._defining_polynomial - - - - - - - - - - - - - - # -------------------------------------------------------------------------------------------- # ============================================================================================ # Utility function to create the roots of a polynomial in an appropriate extension ring @@ -684,20 +662,19 @@ def solve_with_extension(monic_polynomial, root_names=None, var='x', flatten=Fal - ``monic_polynomial`` -- the monic polynomial whose roots should be created - ``root_names`` -- names for the indeterminates needed to define the splitting algebra of the ``monic_polynomial`` (if necessary and possible) - - ``var`` -- (optional string, default 'x') for the indeterminate needed to define the + - ``var`` -- (default: ``'x'``) for the indeterminate needed to define the splitting field of the ``monic_polynomial`` (if necessary and possible) - - ``flatten`` -- (optional boolean, default = True) if set True the roots will not be - given as a list of pairs ``(root, multiplicity)`` but as a list of roots repeated according - to their multiplicity - - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) - to suppress a warning which will be thrown whenever it cannot be checked that - the Galois group of ``monic_polynomial`` is maximal + - ``flatten`` -- (default: ``True``) if ``True`` the roots will not be + given as a list of pairs ``(root, multiplicity)`` but as a list of + roots repeated according to their multiplicity + - ``warning`` -- (default: ``True``) can be used (by setting to ``False``) + to suppress a warning which will be thrown whenever it cannot be checked + that the Galois group of ``monic_polynomial`` is maximal OUTPUT: - List of tuples ``(root, multiplicity)`` respectively list of roots repeated according - to their multiplicity if option ``flatten`` is ``True``. - + List of tuples ``(root, multiplicity)`` respectively list of roots repeated + according to their multiplicity if option ``flatten`` is ``True``. EXAMPLES:: @@ -715,23 +692,23 @@ def solve_with_extension(monic_polynomial, root_names=None, var='x', flatten=Fal sage: _[0][0].parent() Universal Cyclotomic Field """ - def create_roots(monic_polynomial, warning=True): r""" - This internal function creates all roots of a polynomial in an appropriate extension ring - assuming that none of the roots is contained its base ring. + This internal function creates all roots of a polynomial in an + appropriate extension ring assuming that none of the roots is + contained its base ring. - It first tries to create the splitting field of the given polynomial. If this is not - faithful the splitting algebra will be created. + It first tries to create the splitting field of the given polynomial. + If this is not faithful the splitting algebra will be created. INPUT: - - ``monic_polynomial`` -- the monic polynomial whose roots should be created - - ``warning`` -- (optional boolean, default = True) can be used (by setting to False) - to suppress a warning which will be thrown whenever it cannot be checked that - the Galois group of ``monic_polynomial`` is maximal + - ``monic_polynomial`` -- the monic polynomial whose roots should + be created + - ``warning`` -- (default: ``True``) can be used (by setting to ``False``) + to suppress a warning which will be thrown whenever it cannot be + checked that the Galois group of ``monic_polynomial`` is maximal """ - parent = monic_polynomial.parent() base_ring = parent.base_ring() @@ -748,26 +725,26 @@ def create_roots(monic_polynomial, warning=True): # ------------------------------------------------------------------------------------- reset_coercion = False from sage.rings.number_field.number_field import NumberField_generic - if isinstance(base_ring, NumberField_generic): + if isinstance(base_ring, NumberField_generic): reset_coercion = True - elif base_ring.is_finite() == True and base_ring.is_prime_field() == False: + elif base_ring.is_finite() and not base_ring.is_prime_field(): reset_coercion = True - if reset_coercion == True: + if reset_coercion: ext_field._unset_coercions_used() ext_field.register_coercion(embed) ext_field.register_conversion(embed) - verbose("splitting field %s defined" %(ext_field)) + verbose("splitting field %s defined" % (ext_field)) pol_emb = monic_polynomial.change_ring(ext_field) roots = pol_emb.roots() except NotImplementedError: ext_ring = SplittingAlgebra(monic_polynomial, name_list, warning=warning) - verbose("splitting algebra %s defined" %(ext_ring)) + verbose("splitting algebra %s defined" % (ext_ring)) roots = [(r, 1) for r in ext_ring.splitting_roots()] return roots - deg_pol = monic_polynomial.degree() + deg_pol = monic_polynomial.degree() if not root_names: from sage.structure.category_object import normalize_names root_names = normalize_names(deg_pol-1, 'r') @@ -778,13 +755,13 @@ def create_roots(monic_polynomial, warning=True): except (TypeError, ValueError, NotImplementedError): pass - if len(root_list) == 0: + if not root_list: # ------------------------------------------------------------------------------ # no roots found: find roots in an appropriate extension ring # ------------------------------------------------------------------------------ verbose("no roots in base_ring") if len(name_list) > deg_pol -1: - name_list = [name_list[i] for i in range(deg_pol-1 )] + name_list = [name_list[i] for i in range(deg_pol-1)] roots = create_roots(monic_polynomial, warning=warning) else: @@ -799,9 +776,9 @@ def create_roots(monic_polynomial, warning=True): for r, m in root_list: divisor *= (h - r)**m q, r = monic_polynomial.quo_rem(divisor) - if len(name_list) > deg_pol - num_roots -1: - name_list = [name_list[i] for i in range(deg_pol - num_roots -1 )] - verbose("%d root found in base ring, now solving %s" %(num_roots,q)) + if len(name_list) > deg_pol - num_roots - 1: + name_list = [name_list[i] for i in range(deg_pol - num_roots - 1)] + verbose("%d root found in base ring, now solving %s" % (num_roots,q)) missing_roots = create_roots(q, warning=True) roots = root_list + missing_roots else: @@ -812,3 +789,4 @@ def create_roots(monic_polynomial, warning=True): from sage.misc.flatten import flatten return flatten([[rt]*m for rt, m in roots]) return roots + From b8bf1caff7de6c0812d172ff9e980b70e0ec6777 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Jun 2020 10:06:37 +1000 Subject: [PATCH 418/476] 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 419/476] 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 83629f54979e58d77c1ce7deb5122b90e9ef4b41 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Jun 2020 19:54:11 -0700 Subject: [PATCH 420/476] 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 421/476] 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 422/476] 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 423/476] 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 424/476] 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 425/476] 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 426/476] 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 427/476] 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 428/476] 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 429/476] 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 430/476] 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 431/476] 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 432/476] 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 433/476] 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 434/476] 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 435/476] 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 436/476] 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 437/476] 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 438/476] 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 e2dcdeeabb578c37bcf0361c0be3079315e9252c Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sun, 14 Jun 2020 00:16:49 +0200 Subject: [PATCH 439/476] Updated SageMath version to 9.2.beta1 --- 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 64dc3bd1d87..d85786ed487 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.2.beta0, Release Date: 2020-05-28 +SageMath version 9.2.beta1, Release Date: 2020-06-13 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 4c52d48dc9f..87816b1af1c 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=1c21f6e635a7b999032dfb5e3bd569fca562cead -md5=b18610cb53599bfff817e4d1f26d09ef -cksum=763933029 +sha1=b46c24804d86a51b879c6bb187fe5e61b391c35b +md5=e1688a365fcadb8e9a82fbf598973b89 +cksum=189029443 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index c881e48d22b..5560beb0ced 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -982d86df0eb7517b9aed2a911e76ed5dd96fe1ac +2fb1ae046cb7336b4e54f668084d7b773e3a8151 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index a22186797fc..e0b573e5b87 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.beta0' -SAGE_RELEASE_DATE='2020-05-28' -SAGE_VERSION_BANNER='SageMath version 9.2.beta0, Release Date: 2020-05-28' +SAGE_VERSION='9.2.beta1' +SAGE_RELEASE_DATE='2020-06-13' +SAGE_VERSION_BANNER='SageMath version 9.2.beta1, Release Date: 2020-06-13' diff --git a/src/sage/version.py b/src/sage/version.py index 42ea1e04034..951db210d81 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.beta0' -date = '2020-05-28' -banner = 'SageMath version 9.2.beta0, Release Date: 2020-05-28' +version = '9.2.beta1' +date = '2020-06-13' +banner = 'SageMath version 9.2.beta1, Release Date: 2020-06-13' From 10d75ca7d8898a081192cd427e6bd7b7e730e85b Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Sat, 13 Jun 2020 19:34:21 -0400 Subject: [PATCH 440/476] 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 441/476] 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 442/476] 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 443/476] 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 444/476] 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 445/476] 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 446/476] 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 447/476] 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 448/476] 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 e52eece87a4816fb59e81a0886b3a892b0040c47 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Mon, 15 Jun 2020 22:57:49 +0200 Subject: [PATCH 449/476] 29716: correct _first_ngens --- src/sage/algebras/splitting_algebra.py | 33 +++++++------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 024851ea00e..634dd62da36 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -159,11 +159,11 @@ class SplittingAlgebra(PolynomialQuotientRing_domain): sage: all(t^3 -u*t^2 +v*t -w == 0 for t in roots) True sage: xi = ~x; xi - ((-w^-1)*x)*y + (-w^-1)*x^2 + ((w^-1)*u)*x + (w^-1)*x^2 + ((-w^-1)*u)*x + (w^-1)*v sage: ~xi == x True sage: ~y - (w^-1)*x^2 + ((-w^-1)*u)*x + (w^-1)*v + ((-w^-1)*x)*y + (-w^-1)*x^2 + ((w^-1)*u)*x sage: zi = ((w^-1)*x)*y; ~zi -y - x + u @@ -438,8 +438,13 @@ def _first_ngens(self, n): Splitting Algebra of x^3 + (-u^2 + v)*x^2 + (u + v)*x - 1 with roots [X, Y, -Y - X + u^2 - v] over Multivariate Polynomial Ring in u, v over Integer Ring + sage: S._first_ngens(4) + (X, Y, u, v) """ - return self.gens_recursive()[:n] + srts = self.splitting_roots() + k = len(srts)-1 + gens = srts[:k] + list(self.scalar_base_ring().gens()) + return tuple(gens[:n]) def _element_constructor_(self, x): r""" @@ -453,7 +458,7 @@ def _element_constructor_(self, x): sage: S(u + v) u + v sage: S(X*Y + X) - (X + 1)*Y + X*Y + X sage: TestSuite(S).run() # indirect doctest """ if isinstance(x, SplittingAlgebraElement): @@ -576,26 +581,6 @@ def splitting_roots(self): """ return self._splitting_roots - @cached_method - def gens_recursive(self): - r""" - Return all generators recursively. - - EXAMPLES:: - - sage: from sage.algebras.splitting_algebra import SplittingAlgebra - sage: L. = LaurentPolynomialRing(ZZ) - sage: x = polygen(L) - sage: S = SplittingAlgebra(x^3 - u*x^2 + v*x - w, ('X', 'Y')) - sage: S.gens_recursive() - (Y, X, u, v, w) - """ - base_ring = self.base_ring() - res = self.gens() - if isinstance(base_ring, SplittingAlgebra): - return res + base_ring.gens_recursive() - return res + base_ring.gens() - @cached_method def scalar_base_ring(self): r""" From 3de4f74ac9211f4cde61c42e000192ef7907cc0e Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Mon, 15 Jun 2020 19:52:50 -0400 Subject: [PATCH 450/476] 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 451/476] 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 452/476] 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 453/476] 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 454/476] 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 455/476] 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 456/476] 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 457/476] 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 458/476] 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 459/476] 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 460/476] 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 461/476] 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 462/476] 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 463/476] 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 464/476] 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 465/476] 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 466/476] 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 467/476] 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 468/476] 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 469/476] 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 470/476] 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 471/476] 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 472/476] 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 473/476] 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 474/476] 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 475/476] 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 476/476] 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'