From 3375d2139dba607c173aff11cfcaed035f5e0f68 Mon Sep 17 00:00:00 2001 From: Unknown User Date: Sun, 20 Apr 2014 09:15:31 +0000 Subject: [PATCH 001/665] #11529: data structure and enumerated sets for rooted trees. --- src/doc/en/reference/combinat/index.rst | 1 + src/sage/combinat/all.py | 2 + src/sage/combinat/ordered_tree.py | 35 ++ src/sage/combinat/rooted_tree.py | 662 ++++++++++++++++++++++++ 4 files changed, 700 insertions(+) create mode 100644 src/sage/combinat/rooted_tree.py diff --git a/src/doc/en/reference/combinat/index.rst b/src/doc/en/reference/combinat/index.rst index 2f2744634d9..be74dea7229 100644 --- a/src/doc/en/reference/combinat/index.rst +++ b/src/doc/en/reference/combinat/index.rst @@ -56,6 +56,7 @@ Combinatorics sage/combinat/abstract_tree sage/combinat/ordered_tree sage/combinat/binary_tree + sage/combinat/rooted_tree sage/combinat/similarity_class_type sage/combinat/skew_partition sage/combinat/subset diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 08ae21d522f..0b979213a78 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -114,6 +114,8 @@ LabelledOrderedTree, LabelledOrderedTrees) from binary_tree import (BinaryTree, BinaryTrees, LabelledBinaryTree, LabelledBinaryTrees) +from rooted_tree import (RootedTree, RootedTrees, + LabelledRootedTree, LabelledRootedTrees) from combination import Combinations from cartesian_product import CartesianProduct diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index a662238bc5e..75c7fc98a17 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -511,6 +511,41 @@ def left_right_symmetry(self): children.reverse() return OrderedTree(children) + import sage.combinat.ranker + from sage.misc.cachefunc import cached_method + _cayley_ranker = sage.combinat.ranker.on_fly() + @cached_method + def cayley_normalize(self): + """ + sage: (OrderedTree([[],[[]]]).cayley_normalize() == + ... OrderedTree([[[]],[]]).cayley_normalize()) + True + """ + rank, unrank = self._cayley_ranker + with self.clone() as res: + resl = res._get_list() + for i in range(len(resl)): + resl[i] = resl[i].cayley_normalize() + resl.sort(key = rank) + return unrank(rank(res)) + + # TODO !!! + def cayley_normalize_in_place(self): + """ + In place cayley normalization + + EXAMPLES:: + + sage: (OrderedTree([[],[[]]]).cayley_normalize() == + ... OrderedTree([[[]],[]]).cayley_normalize()) + True + """ + rank, unrank = self._cayley_ranker + resl = self._get_list() + for i in range(len(resl)): + resl[i] = resl[i].cayley_normalized() + resl.sort(key = rank) + from sage.categories.sets_cat import Sets, EmptySetError from sage.rings.integer import Integer from sage.sets.non_negative_integers import NonNegativeIntegers diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py new file mode 100644 index 00000000000..375d575417b --- /dev/null +++ b/src/sage/combinat/rooted_tree.py @@ -0,0 +1,662 @@ +r""" +Rooted (Cayley, Unordered) Trees + +AUTHORS: + +- Florent Hivert (2011): initial revision +""" + +import sage +from sage.structure.list_clone import NormalizedClonableList +from sage.combinat.abstract_tree import ( + AbstractClonableTree, AbstractLabelledClonableTree ) +from sage.misc.cachefunc import ( + cached_method, cached_function, cached_in_parent_method ) +from sage.misc.classcall_metaclass import ClasscallMetaclass +from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.misc.misc import srange +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ + +@cached_function +def number_of_rooted_trees(n): + """ + Number of rooted trees with `n` nodes + + Compute the number `a(n)` of rooted trees with `n` nodes using the + recsursive formula ([SL]_): + + .. math:: + + a(n+1) = (1/n) * sum_{k=1..n} ( sum_{d|k} d*a(d) ) * a(n-k+1) + + EXAMPLES:: + + sage: from sage.combinat.rooted_tree import number_of_rooted_trees + sage: [number_of_rooted_trees(i) for i in range(10)] + [0, 1, 1, 2, 4, 9, 20, 48, 115, 286] + + REFERENCES: + + .. [SL] Sloane's A000081 + """ + if n == 0: + return Integer(0) + if n == 1: + return Integer(1) + n = Integer(n) + return sum(sum(d*number_of_rooted_trees(d) for d in k.divisors()) * + number_of_rooted_trees(n-k) + for k in ZZ.range(1, n)) // (n-1) + +class RootedTree(AbstractClonableTree, NormalizedClonableList): + r""" + The class for unordered rooted trees + + One can create a tree from any list (or more generally iterable) of trees + or objects convertible to a tree. + + EXAMPLES:: + + sage: RootedTree([]) + [] + sage: RootedTree([[], [[]]]) + [[], [[]]] + sage: RootedTree([[[]], []]) + [[], [[]]] + """ + + # Standard auto-parent trick + __metaclass__ = ClasscallMetaclass + @staticmethod + def __classcall_private__(cls, *args, **opts): + """ + Ensure that rooted trees created by the enumerated sets and directly + are the same and that they are instance of :class:`RootedTree` + + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTrees_all, RootedTrees_size + sage: issubclass(RootedTrees_all().element_class, RootedTree) + True + sage: t0 = RootedTree([[],[[]]]) + sage: t0.parent() + Rooted trees + sage: type(t0) + + + sage: t1 = RootedTrees()([[],[[]]]) + sage: t1.parent() is t0.parent() + True + sage: type(t1) is type(t0) + True + + sage: t1 = RootedTrees(4)([[],[[]]]) + sage: t1.parent() is t0.parent() + True + sage: type(t1) is type(t0) + True + """ + return cls._auto_parent.element_class(cls._auto_parent, *args, **opts) + + @lazy_class_attribute + def _auto_parent(cls): + """ + The automatic parent of the element of this class + + When calling the constructor of an element of this class, one need a + parent. This class attribute specifies which parent is used. + + EXAMPLES:: + + sage: RootedTree._auto_parent + Rooted trees + sage: RootedTree([]).parent() + Rooted trees + """ + return RootedTrees_all() + + def __init__(self, parent=None, children=[], check=True): + """ + TESTS:: + + sage: t1 = RootedTrees(4)([[],[[]]]) + sage: TestSuite(t1).run() + """ + if (children.__class__ is self.__class__ and + children.parent() == parent): + children = list(children) + else: + children = [self.__class__(parent, x) for x in children] + NormalizedClonableList.__init__(self, parent, children, check=check) + + _cayley_ranker = sage.combinat.ranker.on_fly() + def normalize(self): + r""" + Normalise ``self`` + + There should be no need to call normalize directly as it is called + automatically upon creation and cloning/modification. + + EXAMPLES:: + + sage: RootedTree([[],[[]]]) == RootedTree([[[]],[]]) # indirect doctest + True + sage: rt1 = RootedTree([[],[[]]]) + sage: rt2 = RootedTree([[[]],[]]) + sage: rt1 is rt2 + False + sage: rt1._get_list() is rt2._get_list() + True + """ + # print "Normalizing %s"%self + rank, unrank = self._cayley_ranker + self._require_mutable() + for st in self: + assert st.is_immutable(), "Subtree %s is not normalized"%st + # print self._get_list() + self._get_list().sort(key=rank) + # print self._get_list() + + # ensure unique representation + self.set_immutable() + res = unrank(rank(self)) + if self is not res: + self._set_list(res._get_list()) + + def is_empty(self): + """ + Return if ``self`` is the empty tree + + For rooted trees, returns always ``False`` + + .. note:: this is not the same as ``bool(t)`` which returns whether + ``t`` has some child or not. + + EXAMPLES:: + + sage: t = RootedTrees(4)([[],[[]]]) + sage: t.is_empty() + False + sage: bool(t) + True + """ + return False + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.categories.sets_cat import Sets, EmptySetError +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +import sage.structure.set_factories as factories + +class RootedTreesFactory(factories.SetFactory): + """ + Factory class for rooted trees + """ + + def __call__(self, n=(), policy=None): + """ + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTrees_all, RootedTrees_size + sage: RootedTrees(2) is RootedTrees_size(2) + True + sage: RootedTrees(5).cardinality() + 9 + sage: RootedTrees() is RootedTrees_all() + True + """ + if policy is None: + policy = self._default_policy + + if n == (): + return RootedTrees_all(policy) + elif isinstance(n, (Integer, int)) and n >= 0: + return RootedTrees_size(n, policy) + raise NotImplementedError, "Don't know how to compute %s(%s)"%( + self, n) + + # try: + # from sage.combinat.partition import Partition + # lst = Partition(n) + # except ValueError: + # raise NotImplementedError, "Don't know how to compute %%(%s)"%( + # self, n) + # else: + # return RootedTrees_part(lst, policy) + + def add_constraints(self, cons, (n, st)): + """ + EXAMPLES:: + + sage: RootedTrees.add_constraints((), ((3,), {})) + (3,) + sage: RootedTrees.add_constraints((3,), ((), {})) + (3,) + """ + return cons + n + + @lazy_attribute + def _default_policy(self): + r""" + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTreesFactory + sage: RT = RootedTreesFactory() + sage: RT._default_policy + Set factory policy for with parent Rooted trees[=Rooted tree set factory(())] + """ + return factories.TopMostParentPolicy(self, (), RootedTree) + + def __repr__(self): + """ + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTreesFactory + sage: RootedTreesFactory() + Rooted tree set factory + """ + return "Rooted tree set factory" + +RootedTrees = RootedTreesFactory() + +from sage.sets.non_negative_integers import NonNegativeIntegers +class RootedTrees_all(factories.SetFactoryParent, + DisjointUnionEnumeratedSets): + """ + TESTS:: + + sage: sum(x^len(t) for t in + ... set(RootedTree(t) for t in OrderedTrees(6))) + x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x + sage: sum(x^len(t) for t in RootedTrees(6)) + x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x + """ + @staticmethod + def __classcall_private__(cls, policy=RootedTrees._default_policy): + """ + Input normalization + + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTrees_all + sage: RootedTrees() is RootedTrees_all() + True + """ + return super(RootedTrees_all, cls).__classcall__(cls, policy) + + def __init__(self, policy=RootedTrees._default_policy): + """ + TESTS:: + + sage: TestSuite(RootedTrees()).run() + """ + factories.SetFactoryParent.__init__(self, (), policy, + category = InfiniteEnumeratedSets()) + DisjointUnionEnumeratedSets.__init__( + self, Family(NonNegativeIntegers(), self._of_size), + facade=True, keepkey = False, + category = self.category()) + + def _repr_(self): + r""" + TESTS:: + + sage: RootedTrees() # indirect doctest + Rooted trees + """ + return "Rooted trees" + + def _of_size(self, size): + r""" + The sub-enumerated set of trees of a given size + + Passed to :class:DisjointUnionEnumeratedSets + + TESTS:: + + sage: RootedTrees()._of_size(4) + Rooted trees with 4 nodes + """ + return RootedTrees_size(size, policy=self.facade_policy()) + + def check_element(self, el, check): + r""" + Check that a given tree actually belongs to ``self`` + + See :class:`sage.structure.set_factories.SetFactoryParent` + + TESTS:: + + sage: RT = RootedTrees() + sage: RT([[],[]]) # indirect doctest + [[], []] + """ + pass + + def unlabelled_trees(self): + """ + Returns the set of unlabelled trees associated to ``self`` + + EXAMPLES:: + + sage: RootedTrees().unlabelled_trees() + Rooted trees + """ + return self + + def labelled_trees(self): + """ + Returns the set of unlabelled trees associated to ``self`` + + EXAMPLES:: + + sage: RootedTrees().labelled_trees() + Labelled rooted trees + + As a consequence:: + + sage: lb = RootedTrees()([[],[[], []]]).canonical_labelling() + sage: lb + 1[2[], 3[4[], 5[]]] + sage: lb.__class__ + + sage: lb.parent() + Labelled rooted trees + """ + return LabelledRootedTrees() + + +class RootedTrees_size(factories.SetFactoryParent, UniqueRepresentation): + """ + The enumerated set of rooted trees with a given number of node + + EXAMPLES:: + + """ + @staticmethod + def __classcall_private__(cls, n, policy=RootedTrees._default_policy): + """ + Input normalization + + TESTS:: + + sage: from sage.combinat.rooted_tree import RootedTrees_size + sage: RootedTrees(4) is RootedTrees_size(4) + True + sage: RootedTrees_size(4) is RootedTrees_size(int(4)) + True + """ + return super(RootedTrees_size, cls).__classcall__( + cls, Integer(n), policy) + + def __init__(self, n, policy): + """ + TESTS:: + + sage: for i in range(0, 6): + ... TestSuite(RootedTrees(i)).run() + """ + self._n = n + factories.SetFactoryParent.__init__(self, (n,), policy, + category = FiniteEnumeratedSets()) + + def _repr_(self): + r""" + TESTS:: + + sage: RootedTrees(4) # indirect doctest + Rooted trees with 4 nodes + """ + return "Rooted trees with %s nodes"%(self._n) + + def __iter__(self): + """ + An iterator for ``self`` + + EXAMPLES:: + + sage: from sage.combinat.rooted_tree import * + sage: RootedTrees(0).list() + [] + sage: RootedTrees(1).list() + [[]] + sage: RootedTrees(2).list() + [[[]]] + sage: RootedTrees(3).list() + [[[[]]], [[], []]] + """ + if self._n == 0: + pass + elif self._n == 1: + yield self._element_constructor_([]) + else: + from sage.combinat.partition import Partitions + from sage.combinat.multichoose_nk import MultichooseNK + from sage.combinat.cartesian_product import CartesianProduct + for part in Partitions(self._n - 1): + mults = part.to_exp_dict() + choices = [] + for p, mp in mults.items(): + lp = self.__class__(p, self.policy()).list() + new_choice = MultichooseNK(len(lp), mp).map( + lambda l: [lp[i] for i in l]).list() + choices.append(new_choice) + for c in CartesianProduct(*choices): + yield self._element_constructor_(sum(c, [])) + + def check_element(self, el, check=True): + r""" + Check that a given tree actually belongs to ``self`` + + See :class:`sage.structure.set_factories.SetFactoryParent` + + EXAMPLES:: + + sage: RT3 = RootedTrees(3) + sage: RT3([[],[]]) # indirect doctest + [[], []] + sage: RT3([[],[],[]]) # indirect doctest + Traceback (most recent call last): + ... + ValueError: Wrong number of nodes + """ + if el.node_number() != self._n: + raise ValueError, "Wrong number of nodes" + + def cardinality(self): + r""" + Return the cardinality of ``self`` + + EXAMPLES:: + + sage: RootedTrees(1).cardinality() + 1 + sage: RootedTrees(3).cardinality() + 2 + sage: RootedTrees(0).cardinality() + 0 + """ + return number_of_rooted_trees(self._n) + + +class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): + """ + Labelled rooted trees + + A labellel rooted tree is a rooted tree with a label attached at each node + + INPUT: + + - ``children`` -- a list or tuple or more generally any iterable + of trees or object convertible to trees + - ``label`` -- any Sage object default to ``None`` + + EXAMPLES:: + + sage: x = LabelledRootedTree([], label = 3); x + 3[] + sage: LabelledRootedTree([x, x, x], label = 2) + 2[3[], 3[], 3[]] + sage: LabelledRootedTree((x, x, x), label = 2) + 2[3[], 3[], 3[]] + sage: LabelledRootedTree([[],[[], []]], label = 3) + 3[None[], None[None[], None[]]] + + Children are reordered in a session dependant order: + + sage: y = LabelledRootedTree([], label = 5); x + 3[] + sage: xyy2 = LabelledRootedTree((x, y, y), label = 2); xyy2 #random + 2[3[], 5[], 5[]] + sage: yxy2 = LabelledRootedTree((y, x, y), label = 2); yxy2 #random + 2[3[], 5[], 5[]] + sage: xyy2 == yxy2 + True + + TESTS:: + + sage: xyy2._get_list() is yxy2._get_list() + True + """ + __metaclass__ = ClasscallMetaclass + + @staticmethod + def __classcall_private__(cls, *args, **opts): + """ + Ensure that trees created by the sets and directly are the same and + that they are instance of :class:`LabelledRootedTree` + + TESTS:: + + sage: issubclass(LabelledRootedTrees().element_class, LabelledRootedTree) + True + sage: t0 = LabelledRootedTree([[],[[], []]], label = 3) + sage: t0.parent() + Labelled rooted trees + sage: type(t0) + + """ + return cls._auto_parent.element_class(cls._auto_parent, *args, **opts) + + @lazy_class_attribute + def _auto_parent(cls): + """ + The automatic parent of the element of this class + + When calling the constructor of an element of this class, one need a + parent. This class attribute specifies which parent is used. + + EXAMPLES:: + + sage: LabelledRootedTree._auto_parent + Labelled rooted trees + sage: LabelledRootedTree([], label = 3).parent() + Labelled rooted trees + """ + return LabelledRootedTrees() + + _UnLabelled = RootedTree + + +from sage.rings.infinity import Infinity +class LabelledRootedTrees(UniqueRepresentation, Parent): + """ + This is a parent stub to serve as a factory class for trees with various + labels constraints + + EXAMPLES:: + + sage: LOT = LabelledRootedTrees(); LOT + Labelled rooted trees + sage: x = LOT([], label = 3); x + 3[] + sage: x.parent() is LOT + True + sage: y = LOT([x, x, x], label = 2); y + 2[3[], 3[], 3[]] + sage: y.parent() is LOT + True + """ + def __init__(self, category=None): + """ + TESTS:: + + sage: TestSuite(LabelledRootedTrees()).run() + """ + if category is None: + category = Sets() + Parent.__init__(self, category = category) + + def _repr_(self): + """ + TESTS:: + + sage: LabelledRootedTrees() # indirect doctest + Labelled rooted trees + """ + return "Labelled rooted trees" + + def cardinality(self): + """ + Returns the cardinality of `self` + + EXAMPLE:: + + sage: LabelledRootedTrees().cardinality() + +Infinity + """ + return Infinity + + def _an_element_(self): + """ + Returns a labelled tree + + EXAMPLE:: + + sage: LabelledRootedTrees().an_element() # indirect doctest + toto[3[], 42[3[], 3[]], 5[None[]]] + """ + LT = self._element_constructor_ + t = LT([], label = 3) + t1 = LT([t,t], label = 42) + t2 = LT([[]], label = 5) + return LT([t,t1,t2], label = "toto") + + def _element_constructor_(self, *args, **keywords): + """ + EXAMPLES:: + + sage: T = LabelledRootedTrees() + sage: T([], label=2) # indirect doctest + 2[] + """ + return self.element_class(self, *args, **keywords) + + def unlabelled_trees(self): + """ + Returns the set of unlabelled trees associated to ``self`` + + EXAMPLES:: + + sage: LabelledRootedTrees().unlabelled_trees() + Rooted trees + """ + return RootedTrees_all() + + def labelled_trees(self): + """ + Returns the set of labelled trees associated to ``self`` + + EXAMPLES:: + + sage: LabelledRootedTrees().labelled_trees() + Labelled rooted trees + """ + return self + + Element = LabelledRootedTree + From bad859055dcfc8e014125b31e25702359d6e462a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 20 Apr 2014 11:27:08 +0200 Subject: [PATCH 002/665] trac #11529 pyflakes details --- src/sage/combinat/rooted_tree.py | 53 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 375d575417b..4534c48b2b7 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -6,17 +6,27 @@ - Florent Hivert (2011): initial revision """ -import sage from sage.structure.list_clone import NormalizedClonableList from sage.combinat.abstract_tree import ( AbstractClonableTree, AbstractLabelledClonableTree ) -from sage.misc.cachefunc import ( - cached_method, cached_function, cached_in_parent_method ) +from sage.misc.cachefunc import cached_function +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.sets_cat import Sets from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute -from sage.misc.misc import srange from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.rings.infinity import Infinity +from sage.combinat.ranker import on_fly +import sage.structure.set_factories as factories + + @cached_function def number_of_rooted_trees(n): @@ -49,6 +59,7 @@ def number_of_rooted_trees(n): number_of_rooted_trees(n-k) for k in ZZ.range(1, n)) // (n-1) + class RootedTree(AbstractClonableTree, NormalizedClonableList): r""" The class for unordered rooted trees @@ -72,7 +83,7 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): def __classcall_private__(cls, *args, **opts): """ Ensure that rooted trees created by the enumerated sets and directly - are the same and that they are instance of :class:`RootedTree` + are the same and that they are instances of :class:`RootedTree` TESTS:: @@ -104,7 +115,7 @@ def _auto_parent(cls): """ The automatic parent of the element of this class - When calling the constructor of an element of this class, one need a + When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. EXAMPLES:: @@ -130,13 +141,14 @@ def __init__(self, parent=None, children=[], check=True): children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) - _cayley_ranker = sage.combinat.ranker.on_fly() + _cayley_ranker = on_fly() def normalize(self): r""" Normalise ``self`` - There should be no need to call normalize directly as it is called - automatically upon creation and cloning/modification. + There should be no need to call ``normalize`` directly as it + is called automatically upon creation and + cloning/modification. EXAMPLES:: @@ -153,7 +165,7 @@ def normalize(self): rank, unrank = self._cayley_ranker self._require_mutable() for st in self: - assert st.is_immutable(), "Subtree %s is not normalized"%st + assert st.is_immutable(), "Subtree {} is not normalized".format(st) # print self._get_list() self._get_list().sort(key=rank) # print self._get_list() @@ -183,14 +195,6 @@ def is_empty(self): """ return False -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent -from sage.categories.sets_cat import Sets, EmptySetError -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets -from sage.sets.family import Family -import sage.structure.set_factories as factories class RootedTreesFactory(factories.SetFactory): """ @@ -216,15 +220,14 @@ def __call__(self, n=(), policy=None): return RootedTrees_all(policy) elif isinstance(n, (Integer, int)) and n >= 0: return RootedTrees_size(n, policy) - raise NotImplementedError, "Don't know how to compute %s(%s)"%( - self, n) + raise NotImplementedError("Do not know how to compute {}({})".format(self, n)) # try: # from sage.combinat.partition import Partition # lst = Partition(n) # except ValueError: - # raise NotImplementedError, "Don't know how to compute %%(%s)"%( - # self, n) + # raise NotImplementedError("Don't know how to compute %%(%s)"%( + # self, n)) # else: # return RootedTrees_part(lst, policy) @@ -263,7 +266,8 @@ def __repr__(self): RootedTrees = RootedTreesFactory() -from sage.sets.non_negative_integers import NonNegativeIntegers + + class RootedTrees_all(factories.SetFactoryParent, DisjointUnionEnumeratedSets): """ @@ -465,7 +469,7 @@ def check_element(self, el, check=True): ValueError: Wrong number of nodes """ if el.node_number() != self._n: - raise ValueError, "Wrong number of nodes" + raise ValueError("Wrong number of nodes") def cardinality(self): r""" @@ -562,7 +566,6 @@ def _auto_parent(cls): _UnLabelled = RootedTree -from sage.rings.infinity import Infinity class LabelledRootedTrees(UniqueRepresentation, Parent): """ This is a parent stub to serve as a factory class for trees with various From f0bd1323350839e28c20e43d6e813e73b4880278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 21 Apr 2014 10:01:05 +0200 Subject: [PATCH 003/665] trac #11529 minor details --- src/sage/combinat/rooted_tree.py | 112 +++++++++++++++---------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 4534c48b2b7..6b4de34d4ca 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -6,35 +6,34 @@ - Florent Hivert (2011): initial revision """ -from sage.structure.list_clone import NormalizedClonableList -from sage.combinat.abstract_tree import ( - AbstractClonableTree, AbstractLabelledClonableTree ) -from sage.misc.cachefunc import cached_function from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_cat import Sets +from sage.combinat.ranker import on_fly +from sage.combinat.abstract_tree import ( + AbstractClonableTree, AbstractLabelledClonableTree) +from sage.misc.cachefunc import cached_function from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.structure.list_clone import NormalizedClonableList from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.infinity import Infinity -from sage.combinat.ranker import on_fly import sage.structure.set_factories as factories - @cached_function def number_of_rooted_trees(n): """ Number of rooted trees with `n` nodes Compute the number `a(n)` of rooted trees with `n` nodes using the - recsursive formula ([SL]_): + recursive formula ([SL000081]_): .. math:: @@ -48,24 +47,24 @@ def number_of_rooted_trees(n): REFERENCES: - .. [SL] Sloane's A000081 + .. [SL000081] Sloane's :oeis:`A000081` """ if n == 0: return Integer(0) if n == 1: return Integer(1) n = Integer(n) - return sum(sum(d*number_of_rooted_trees(d) for d in k.divisors()) * - number_of_rooted_trees(n-k) - for k in ZZ.range(1, n)) // (n-1) + return sum(sum(d * number_of_rooted_trees(d) for d in k.divisors()) * + number_of_rooted_trees(n - k) + for k in ZZ.range(1, n)) // (n - 1) class RootedTree(AbstractClonableTree, NormalizedClonableList): r""" The class for unordered rooted trees - One can create a tree from any list (or more generally iterable) of trees - or objects convertible to a tree. + One can create a tree from any list (or more generally iterable) + of trees or objects convertible to a tree. EXAMPLES:: @@ -76,9 +75,9 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): sage: RootedTree([[[]], []]) [[], [[]]] """ - # Standard auto-parent trick __metaclass__ = ClasscallMetaclass + @staticmethod def __classcall_private__(cls, *args, **opts): """ @@ -87,7 +86,7 @@ def __classcall_private__(cls, *args, **opts): TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all, RootedTrees_size + sage: from sage.combinat.rooted_tree import RootedTrees_all sage: issubclass(RootedTrees_all().element_class, RootedTree) True sage: t0 = RootedTree([[],[[]]]) @@ -113,7 +112,7 @@ def __classcall_private__(cls, *args, **opts): @lazy_class_attribute def _auto_parent(cls): """ - The automatic parent of the element of this class + The automatic parent of the elements of this class When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. @@ -134,41 +133,41 @@ def __init__(self, parent=None, children=[], check=True): sage: t1 = RootedTrees(4)([[],[[]]]) sage: TestSuite(t1).run() """ - if (children.__class__ is self.__class__ and - children.parent() == parent): + tst = (children.__class__ is self.__class__ + and children.parent() == parent) + if tst: children = list(children) else: children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) _cayley_ranker = on_fly() + def normalize(self): r""" - Normalise ``self`` + Normalize ``self`` There should be no need to call ``normalize`` directly as it - is called automatically upon creation and - cloning/modification. + is called automatically upon creation and cloning or + modification. EXAMPLES:: - sage: RootedTree([[],[[]]]) == RootedTree([[[]],[]]) # indirect doctest + sage: RT = RootedTree + sage: RT([[],[[]]]) == RT([[[]],[]]) # indirect doctest True - sage: rt1 = RootedTree([[],[[]]]) - sage: rt2 = RootedTree([[[]],[]]) + sage: rt1 = RT([[],[[]]]) + sage: rt2 = RT([[[]],[]]) sage: rt1 is rt2 False sage: rt1._get_list() is rt2._get_list() True """ - # print "Normalizing %s"%self rank, unrank = self._cayley_ranker self._require_mutable() for st in self: assert st.is_immutable(), "Subtree {} is not normalized".format(st) - # print self._get_list() self._get_list().sort(key=rank) - # print self._get_list() # ensure unique representation self.set_immutable() @@ -177,13 +176,15 @@ def normalize(self): self._set_list(res._get_list()) def is_empty(self): - """ + r""" Return if ``self`` is the empty tree For rooted trees, returns always ``False`` - .. note:: this is not the same as ``bool(t)`` which returns whether - ``t`` has some child or not. + .. NOTE:: + + This is not the same as ``bool(t)`` which returns whether + ``t`` has some child or not. EXAMPLES:: @@ -220,7 +221,8 @@ def __call__(self, n=(), policy=None): return RootedTrees_all(policy) elif isinstance(n, (Integer, int)) and n >= 0: return RootedTrees_size(n, policy) - raise NotImplementedError("Do not know how to compute {}({})".format(self, n)) + msg = "Do not know how to compute {}({})".format(self, n) + raise NotImplementedError(msg) # try: # from sage.combinat.partition import Partition @@ -240,7 +242,7 @@ def add_constraints(self, cons, (n, st)): sage: RootedTrees.add_constraints((3,), ((), {})) (3,) """ - return cons + n + return cons + n @lazy_attribute def _default_policy(self): @@ -267,7 +269,6 @@ def __repr__(self): RootedTrees = RootedTreesFactory() - class RootedTrees_all(factories.SetFactoryParent, DisjointUnionEnumeratedSets): """ @@ -299,11 +300,11 @@ def __init__(self, policy=RootedTrees._default_policy): sage: TestSuite(RootedTrees()).run() """ factories.SetFactoryParent.__init__(self, (), policy, - category = InfiniteEnumeratedSets()) + category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), self._of_size), - facade=True, keepkey = False, - category = self.category()) + facade=True, keepkey=False, + category=self.category()) def _repr_(self): r""" @@ -354,7 +355,7 @@ def unlabelled_trees(self): def labelled_trees(self): """ - Returns the set of unlabelled trees associated to ``self`` + Returns the set of labelled trees associated to ``self`` EXAMPLES:: @@ -376,7 +377,7 @@ def labelled_trees(self): class RootedTrees_size(factories.SetFactoryParent, UniqueRepresentation): """ - The enumerated set of rooted trees with a given number of node + The enumerated set of rooted trees with a given number of nodes EXAMPLES:: @@ -402,11 +403,11 @@ def __init__(self, n, policy): TESTS:: sage: for i in range(0, 6): - ... TestSuite(RootedTrees(i)).run() + ....: TestSuite(RootedTrees(i)).run() """ self._n = n factories.SetFactoryParent.__init__(self, (n,), policy, - category = FiniteEnumeratedSets()) + category=FiniteEnumeratedSets()) def _repr_(self): r""" @@ -415,7 +416,7 @@ def _repr_(self): sage: RootedTrees(4) # indirect doctest Rooted trees with 4 nodes """ - return "Rooted trees with %s nodes"%(self._n) + return "Rooted trees with {} nodes".format(self._n) def __iter__(self): """ @@ -491,7 +492,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): """ Labelled rooted trees - A labellel rooted tree is a rooted tree with a label attached at each node + A labelled rooted tree is a rooted tree with a label attached at each node INPUT: @@ -532,7 +533,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): def __classcall_private__(cls, *args, **opts): """ Ensure that trees created by the sets and directly are the same and - that they are instance of :class:`LabelledRootedTree` + that they are instances of :class:`LabelledRootedTree` TESTS:: @@ -551,7 +552,7 @@ def _auto_parent(cls): """ The automatic parent of the element of this class - When calling the constructor of an element of this class, one need a + When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. EXAMPLES:: @@ -573,15 +574,15 @@ class LabelledRootedTrees(UniqueRepresentation, Parent): EXAMPLES:: - sage: LOT = LabelledRootedTrees(); LOT + sage: LRT = LabelledRootedTrees(); LRT Labelled rooted trees - sage: x = LOT([], label = 3); x + sage: x = LRT([], label = 3); x 3[] - sage: x.parent() is LOT + sage: x.parent() is LRT True - sage: y = LOT([x, x, x], label = 2); y + sage: y = LRT([x, x, x], label = 2); y 2[3[], 3[], 3[]] - sage: y.parent() is LOT + sage: y.parent() is LRT True """ def __init__(self, category=None): @@ -592,7 +593,7 @@ def __init__(self, category=None): """ if category is None: category = Sets() - Parent.__init__(self, category = category) + Parent.__init__(self, category=category) def _repr_(self): """ @@ -624,10 +625,10 @@ def _an_element_(self): toto[3[], 42[3[], 3[]], 5[None[]]] """ LT = self._element_constructor_ - t = LT([], label = 3) - t1 = LT([t,t], label = 42) - t2 = LT([[]], label = 5) - return LT([t,t1,t2], label = "toto") + t = LT([], label=3) + t1 = LT([t, t], label=42) + t2 = LT([[]], label=5) + return LT([t, t1, t2], label="toto") def _element_constructor_(self, *args, **keywords): """ @@ -662,4 +663,3 @@ def labelled_trees(self): return self Element = LabelledRootedTree - From 5a15e0796b249344ef66b5a6f9a1d7e1a17107f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 21 Apr 2014 10:14:52 +0200 Subject: [PATCH 004/665] trac #11529 trying to make it work --- src/sage/combinat/rooted_tree.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 6b4de34d4ca..039bd4c7175 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -269,7 +269,7 @@ def __repr__(self): RootedTrees = RootedTreesFactory() -class RootedTrees_all(factories.SetFactoryParent, +class RootedTrees_all(factories.ParentWithSetFactory, DisjointUnionEnumeratedSets): """ TESTS:: @@ -299,7 +299,7 @@ def __init__(self, policy=RootedTrees._default_policy): sage: TestSuite(RootedTrees()).run() """ - factories.SetFactoryParent.__init__(self, (), policy, + factories.ParentWithSetFactory.__init__(self, (), policy, category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), self._of_size), @@ -332,7 +332,7 @@ def check_element(self, el, check): r""" Check that a given tree actually belongs to ``self`` - See :class:`sage.structure.set_factories.SetFactoryParent` + See :class:`sage.structure.set_factories.ParentWithSetFactory` TESTS:: @@ -375,7 +375,7 @@ def labelled_trees(self): return LabelledRootedTrees() -class RootedTrees_size(factories.SetFactoryParent, UniqueRepresentation): +class RootedTrees_size(factories.ParentWithSetFactory, UniqueRepresentation): """ The enumerated set of rooted trees with a given number of nodes @@ -406,7 +406,7 @@ def __init__(self, n, policy): ....: TestSuite(RootedTrees(i)).run() """ self._n = n - factories.SetFactoryParent.__init__(self, (n,), policy, + factories.ParentWithSetFactory.__init__(self, (n,), policy, category=FiniteEnumeratedSets()) def _repr_(self): @@ -457,7 +457,7 @@ def check_element(self, el, check=True): r""" Check that a given tree actually belongs to ``self`` - See :class:`sage.structure.set_factories.SetFactoryParent` + See :class:`sage.structure.set_factories.ParentWithSetFactory` EXAMPLES:: From 5849b284ed4e139efebc38a8f1d7bbf8a09e301b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 21 Apr 2014 10:21:16 +0200 Subject: [PATCH 005/665] trac #11529 tests seem to pass --- src/sage/combinat/ordered_tree.py | 18 ++++++++++-------- src/sage/combinat/rooted_tree.py | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 75c7fc98a17..6463c2c830c 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -22,6 +22,13 @@ from sage.combinat.abstract_tree import (AbstractClonableTree, AbstractLabelledClonableTree) from sage.combinat.combinatorial_map import combinatorial_map +from sage.misc.cachefunc import cached_method +from sage.categories.sets_cat import Sets, EmptySetError +from sage.rings.integer import Integer +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.sets.family import Family +from sage.misc.cachefunc import cached_method class OrderedTree(AbstractClonableTree, ClonableList): @@ -512,8 +519,8 @@ def left_right_symmetry(self): return OrderedTree(children) import sage.combinat.ranker - from sage.misc.cachefunc import cached_method _cayley_ranker = sage.combinat.ranker.on_fly() + @cached_method def cayley_normalize(self): """ @@ -546,12 +553,6 @@ def cayley_normalize_in_place(self): resl[i] = resl[i].cayley_normalized() resl.sort(key = rank) -from sage.categories.sets_cat import Sets, EmptySetError -from sage.rings.integer import Integer -from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets -from sage.sets.family import Family -from sage.misc.cachefunc import cached_method # Abstract class to serve as a Factory no instance are created. class OrderedTrees(UniqueRepresentation, Parent): @@ -623,6 +624,7 @@ def leaf(self): """ return self([]) + class OrderedTrees_all(DisjointUnionEnumeratedSets, OrderedTrees): """ The set of all ordered trees. @@ -694,7 +696,7 @@ def unlabelled_trees(self): def labelled_trees(self): """ - Return the set of unlabelled trees associated to ``self`` + Return the set of labelled trees associated to ``self`` EXAMPLES:: diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 039bd4c7175..2788c5c8989 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -300,7 +300,7 @@ def __init__(self, policy=RootedTrees._default_policy): sage: TestSuite(RootedTrees()).run() """ factories.ParentWithSetFactory.__init__(self, (), policy, - category=InfiniteEnumeratedSets()) + category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), self._of_size), facade=True, keepkey=False, @@ -407,7 +407,7 @@ def __init__(self, n, policy): """ self._n = n factories.ParentWithSetFactory.__init__(self, (n,), policy, - category=FiniteEnumeratedSets()) + category=FiniteEnumeratedSets()) def _repr_(self): r""" From 580b95f57757a38fbd32b4045253820a21b9aa6d Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 7 Apr 2014 21:30:20 +0100 Subject: [PATCH 006/665] Trac 15486: speed up NumberField_generic.zeta() and DirichletGroup() --- src/sage/modular/dirichlet.py | 16 ++++++------- .../rings/finite_rings/integer_mod_ring.py | 2 +- src/sage/rings/number_field/number_field.py | 23 ++++++++++--------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index cdba0cb4e9b..d61919b0a4e 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1779,15 +1779,13 @@ def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, names=None, if zeta is None: e = rings.IntegerModRing(modulus).unit_group_exponent() - try: - zeta = base_ring.zeta(e) - zeta_order = zeta.multiplicative_order() - except (TypeError, ValueError, ArithmeticError): - zeta = base_ring.zeta(base_ring.zeta_order()) - n = zeta.multiplicative_order() - zeta_order = arith.GCD(e,n) - zeta = zeta**(n//zeta_order) - + for d in reversed(e.divisors()): + try: + zeta = base_ring.zeta(d) + zeta_order = d + break + except ValueError: + pass elif zeta_order is None: zeta_order = zeta.multiplicative_order() diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index fc0fdf6d20f..a764f786b61 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -1197,7 +1197,7 @@ def unit_group_exponent(self): a.append(2) elif r>2: a.append(2**(r-2)) - return int(LCM(a)) + return LCM(a) def unit_group_order(self): """ diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 9ca1e846419..2298f9557d9 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5585,18 +5585,19 @@ def zeta(self, n=2, all=False): return [K(-1)] else: return K(-1) - N = K.zeta_order() - if n.divides(N): - z = K.primitive_root_of_unity() ** (N//n) - if all: - return [z**i for i in n.coprime_integers(n)] - else: - return z - else: + + # First check if the degree of K is compatible with an + # inclusion QQ(\zeta_n) -> K. + if sage.rings.arith.euler_phi(n).divides(K.absolute_degree()): + # Factor the n-th cyclotomic polynomial over K. + f = K.absolute_polynomial().change_variable_name('y') + factors = pari.polcyclo(n).factornf(f).component(1) + roots = [K(-g.polcoeff(0)) for g in factors if g.poldegree() == 1] if all: - return [] - else: - raise ValueError("There are no %s roots of unity in self."%n.ordinal_str()) + return roots + if roots: + return roots[0] + raise ValueError("There are no %s roots of unity in self." % n.ordinal_str()) def zeta_order(self): r""" From bedb031f90f78408cdda2bb9b5bd56d519d59c75 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 7 Apr 2014 22:22:42 +0100 Subject: [PATCH 007/665] Trac 15486: update doctests --- src/doc/de/tutorial/tour_advanced.rst | 4 ++-- src/doc/en/tutorial/tour_advanced.rst | 4 ++-- src/doc/fr/tutorial/tour_advanced.rst | 4 ++-- src/doc/ru/tutorial/tour_advanced.rst | 4 ++-- src/sage/modular/modform/constructor.py | 2 +- src/sage/rings/number_field/number_field.py | 8 ++++---- src/sage/rings/number_field/order.py | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/doc/de/tutorial/tour_advanced.rst b/src/doc/de/tutorial/tour_advanced.rst index b5fff8ed8c6..9308ac790f0 100644 --- a/src/doc/de/tutorial/tour_advanced.rst +++ b/src/doc/de/tutorial/tour_advanced.rst @@ -359,12 +359,12 @@ Nun berechnen wir mehrere Invarianten von ``G``: sage: G.gens() (Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, - Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -i) + Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i) sage: G.unit_gens() (11, 17) sage: G.zeta() - -i + i sage: G.zeta_order() 4 diff --git a/src/doc/en/tutorial/tour_advanced.rst b/src/doc/en/tutorial/tour_advanced.rst index 5069d4bcab5..32717e43892 100644 --- a/src/doc/en/tutorial/tour_advanced.rst +++ b/src/doc/en/tutorial/tour_advanced.rst @@ -357,12 +357,12 @@ We next compute several invariants of ``G``: sage: G.gens() (Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, - Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -i) + Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i) sage: G.unit_gens() (11, 17) sage: G.zeta() - -i + i sage: G.zeta_order() 4 diff --git a/src/doc/fr/tutorial/tour_advanced.rst b/src/doc/fr/tutorial/tour_advanced.rst index fbaa3ac76fb..92e300dad68 100644 --- a/src/doc/fr/tutorial/tour_advanced.rst +++ b/src/doc/fr/tutorial/tour_advanced.rst @@ -357,12 +357,12 @@ Nous calculons ensuite différents invariants de ``G``: sage: G.gens() (Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, - Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -i) + Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i) sage: G.unit_gens() (11, 17) sage: G.zeta() - -i + i sage: G.zeta_order() 4 diff --git a/src/doc/ru/tutorial/tour_advanced.rst b/src/doc/ru/tutorial/tour_advanced.rst index d9ab2c59220..b7a64a75b9a 100644 --- a/src/doc/ru/tutorial/tour_advanced.rst +++ b/src/doc/ru/tutorial/tour_advanced.rst @@ -322,12 +322,12 @@ Sage может вычислить тороидальный идеал непл sage: G.gens() (Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, - Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -i) + Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i) sage: G.unit_gens() (11, 17) sage: G.zeta() - -i + i sage: G.zeta_order() 4 diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index d5e5152f4ab..563bf44c948 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -430,7 +430,7 @@ def Newforms(group, weight=2, base_ring=None, names=None): base field that is not minimal for that character:: sage: K. = QuadraticField(-1) - sage: chi = DirichletGroup(5, K)[3] + sage: chi = DirichletGroup(5, K)([i]) # character mapping 2 to i sage: len(Newforms(chi, 7, names='a')) 1 sage: x = polygen(K); L. = K.extension(x^2 - 402*i) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 2298f9557d9..3433bb60fdb 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5539,9 +5539,9 @@ def zeta(self, n=2, all=False): sage: K.zeta(2, all=True) [-1] sage: K.zeta(3) - -1/2*z - 1/2 + 1/2*z - 1/2 sage: K.zeta(3, all=True) - [-1/2*z - 1/2, 1/2*z - 1/2] + [1/2*z - 1/2, -1/2*z - 1/2] sage: K.zeta(4) Traceback (most recent call last): ... @@ -5552,9 +5552,9 @@ def zeta(self, n=2, all=False): sage: r. = QQ[] sage: K. = NumberField(x^2+1) sage: K.zeta(4) - -b + b sage: K.zeta(4,all=True) - [-b, b] + [b, -b] sage: K.zeta(3) Traceback (most recent call last): ... diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 99fe0158f10..a3e77863a1d 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -624,7 +624,7 @@ def zeta(self, n=2, all=False): sage: F. = NumberField(x**2+3) sage: F.ring_of_integers().zeta(6) - -1/2*alpha + 1/2 + 1/2*alpha + 1/2 sage: O = F.order([3*alpha]) sage: O.zeta(3) Traceback (most recent call last): From f84927471da053a934464b4e6ae0c4d958f677b7 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 7 Apr 2014 22:29:50 +0100 Subject: [PATCH 008/665] Trac 15486: add doctest --- src/sage/modular/modform/constructor.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 563bf44c948..5af635579de 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -439,11 +439,19 @@ def Newforms(group, weight=2, base_ring=None, names=None): sage: sorted([N[0][2], N[1][2]]) == sorted([1/2*c - 5/2*i - 5/2, -1/2*c - 5/2*i - 5/2]) True + TESTS: + We test that :trac:`8630` is fixed:: sage: chi = DirichletGroup(109, CyclotomicField(3)).0 sage: CuspForms(chi, 2, base_ring = CyclotomicField(9)) Cuspidal subspace of dimension 8 of Modular Forms space of dimension 10, character [zeta3 + 1] and weight 2 over Cyclotomic Field of order 9 and degree 6 + + Check that :trac:`15486` is fixed (this used to take over a day):: + + sage: N = Newforms(719, names='a'); len(N) # long time (3 s) + 3 + """ return CuspForms(group, weight, base_ring).newforms(names) From be21430e31d03f77405df68b91f83e90352aaac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 8 Jun 2014 22:10:30 +0200 Subject: [PATCH 009/665] trac #11529 two more useful methods --- src/sage/combinat/rooted_tree.py | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 2788c5c8989..8b56db307c4 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -374,6 +374,56 @@ def labelled_trees(self): """ return LabelledRootedTrees() + def graft_list(self, other): + """ + Return the list of trees obtained by grafting ``other`` on ``self`` + + This is useful for free pre-Lie algebras. + + EXAMPLES:: + + sage: RT = RootedTree + sage: x = RT([]) + sage: y = RT([x, x]) + sage: x.graft_list(x) + [[[]]] + sage: y.graft_list(x) + [[[], [], []], [[], [[]]], [[], [[]]]] + """ + resu = [] + with self.clone() as t: + t.append(other) + resu += [t] + for i, sub in enumerate(self): + for new_sub in sub.graft_list(other): + with self.clone() as t: + t[i] = new_sub + resu += [t] + return resu + + def graft_on_root(self, other): + """ + Return the tree obtained by grafting ``other`` on the root of ``self`` + + This is useful for free Nap algebras. + + EXAMPLES:: + + sage: RT = RootedTree + sage: x = RT([]) + sage: y = RT([x, x]) + sage: x.graft_on_root(x) + [[]] + sage: y.graft_on_root(x) + [[], [], []] + sage: x.graft_on_root(y) + [[[], []]] + """ + with self.clone() as t: + t.append(other) + resu = t + return resu + class RootedTrees_size(factories.ParentWithSetFactory, UniqueRepresentation): """ From 6bf100e78976d7c56b5ba8843b40e80dec3265ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 9 Jun 2014 09:32:08 +0200 Subject: [PATCH 010/665] trac #11529 make tests pass --- src/sage/combinat/rooted_tree.py | 100 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 8b56db307c4..5f387823365 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -196,6 +196,56 @@ def is_empty(self): """ return False + def graft_list(self, other): + """ + Return the list of trees obtained by grafting ``other`` on ``self`` + + This is useful for free pre-Lie algebras. + + EXAMPLES:: + + sage: RT = RootedTree + sage: x = RT([]) + sage: y = RT([x, x]) + sage: x.graft_list(x) + [[[]]] + sage: y.graft_list(x) + [[[], [], []], [[], [[]]], [[], [[]]]] + """ + resu = [] + with self.clone() as t: + t.append(other) + resu += [t] + for i, sub in enumerate(self): + for new_sub in sub.graft_list(other): + with self.clone() as t: + t[i] = new_sub + resu += [t] + return resu + + def graft_on_root(self, other): + """ + Return the tree obtained by grafting ``other`` on the root of ``self`` + + This is useful for free Nap algebras. + + EXAMPLES:: + + sage: RT = RootedTree + sage: x = RT([]) + sage: y = RT([x, x]) + sage: x.graft_on_root(x) + [[]] + sage: y.graft_on_root(x) + [[], [], []] + sage: x.graft_on_root(y) + [[[], []]] + """ + with self.clone() as t: + t.append(other) + resu = t + return resu + class RootedTreesFactory(factories.SetFactory): """ @@ -374,56 +424,6 @@ def labelled_trees(self): """ return LabelledRootedTrees() - def graft_list(self, other): - """ - Return the list of trees obtained by grafting ``other`` on ``self`` - - This is useful for free pre-Lie algebras. - - EXAMPLES:: - - sage: RT = RootedTree - sage: x = RT([]) - sage: y = RT([x, x]) - sage: x.graft_list(x) - [[[]]] - sage: y.graft_list(x) - [[[], [], []], [[], [[]]], [[], [[]]]] - """ - resu = [] - with self.clone() as t: - t.append(other) - resu += [t] - for i, sub in enumerate(self): - for new_sub in sub.graft_list(other): - with self.clone() as t: - t[i] = new_sub - resu += [t] - return resu - - def graft_on_root(self, other): - """ - Return the tree obtained by grafting ``other`` on the root of ``self`` - - This is useful for free Nap algebras. - - EXAMPLES:: - - sage: RT = RootedTree - sage: x = RT([]) - sage: y = RT([x, x]) - sage: x.graft_on_root(x) - [[]] - sage: y.graft_on_root(x) - [[], [], []] - sage: x.graft_on_root(y) - [[[], []]] - """ - with self.clone() as t: - t.append(other) - resu = t - return resu - class RootedTrees_size(factories.ParentWithSetFactory, UniqueRepresentation): """ From a0a9f23a7f9d4b12d7f89d6e82c37a251e114959 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 22 Jun 2014 23:20:12 +0200 Subject: [PATCH 011/665] display of numbers in tikz output --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 07624500ba7..2b83bd81cfb 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1202,7 +1202,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1323,7 +1323,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1486,7 +1486,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From 6e8cc4f842142f1aa97b84e299ab6169bda2412a Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 23 Jun 2014 10:07:35 +0200 Subject: [PATCH 012/665] fix tikz output for plot of projections of polytopes --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 2b83bd81cfb..1b563200eb3 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1202,7 +1202,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(4) for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1323,7 +1323,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1486,7 +1486,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From 89391810175b3a73be98352dd2e8f140e6a34b1a Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 23 Jun 2014 10:14:36 +0200 Subject: [PATCH 013/665] forgot to change one line --- src/sage/geometry/polyhedron/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 1b563200eb3..be4d14bc6a1 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1202,7 +1202,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect From 2642c7af1a6924da872fb144235531bba5670994 Mon Sep 17 00:00:00 2001 From: "moritz@math.fu-berlin.de" Date: Mon, 23 Jun 2014 12:58:53 +0200 Subject: [PATCH 014/665] corrected string formatting --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index be4d14bc6a1..14563dcafb9 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1202,7 +1202,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1323,7 +1323,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1486,7 +1486,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From 7abb19767605b3e2a1d10e72748b6e87a537c8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 1 Jul 2014 15:29:05 -0500 Subject: [PATCH 015/665] 11111: Imported trac_11111-finite_dimensional_modules-nt.patch from the Sage-Combinat queue (+ minor proofreading) * Echelon form of list of vectors * Submodules and quotients * Example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver * Category SemisimpleAlgebras(...) * Finite group algebras are semisimple in characteristic 0 * Center, radical, and semisimple quotient of a finite dimensional algebra * Annihilator * Matrix and inverse of module morphisms * Some more support for term orders in CombinatorialFreeModule * map_support_skip_none in ModulesWithBasis --- src/sage/categories/algebras.py | 24 ++ src/sage/categories/all.py | 1 + .../finite_dimensional_algebras_with_basis.py | 126 +++++++ .../finite_dimensional_algebras_with_basis.py | 351 ++++++++++++++++-- .../finite_dimensional_modules_with_basis.py | 163 +++++++- src/sage/categories/modules_with_basis.py | 129 +++++++ src/sage/categories/semisimple_algebras.py | 55 +++ src/sage/combinat/free_module.py | 72 +++- .../modules/subquotient_module_with_basis.py | 207 +++++++++++ 9 files changed, 1097 insertions(+), 31 deletions(-) create mode 100644 src/sage/categories/examples/finite_dimensional_algebras_with_basis.py create mode 100644 src/sage/categories/semisimple_algebras.py create mode 100644 src/sage/modules/subquotient_module_with_basis.py diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 00bd5597642..eabf44888e5 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -20,6 +20,7 @@ from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.cartesian_product import CartesianProductsCategory +from sage.categories.quotients import QuotientsCategory from sage.categories.dual import DualObjectsCategory from sage.categories.tensor import TensorProductsCategory from sage.categories.associative_algebras import AssociativeAlgebras @@ -115,6 +116,29 @@ def _div_(self, y): """ return self.parent().product(self, ~y) + class Quotients(QuotientsCategory): + + class ParentMethods: + + def algebra_generators(self): + r""" + Return algebra generators for ``self``. + + This implementation retracts the algebra generators + from the ambient algebra. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: S = A.semisimple_quotient() + sage: S.algebra_generators() + Finite family {'y': B['y'], 'x': B['x'], 'b': 0, 'a': 0} + + .. TODO:: this could possibly remove the elements that retract to zero + """ + return self.ambient().algebra_generators().map(self.retract) + class CartesianProducts(CartesianProductsCategory): """ The category of algebras constructed as cartesian products of algebras diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 233ea32ce9e..c7397eb38fb 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -74,6 +74,7 @@ from monoid_algebras import MonoidAlgebras from group_algebras import GroupAlgebras from matrix_algebras import MatrixAlgebras +from semisimple_algebras import SemisimpleAlgebras # ideals from ring_ideals import RingIdeals diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py new file mode 100644 index 00000000000..6eca38c288d --- /dev/null +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -0,0 +1,126 @@ +r""" +Examples of finite dimensional algebras with basis +""" +#***************************************************************************** +# Copyright (C) 2008-2009 Franco Saliola +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.categories.all import FiniteDimensionalAlgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule + +class KroneckerQuiverPathAlgebra(CombinatorialFreeModule): + r""" + An example of a finite dimensional algebra with basis: the path algebra of + the Kronecker quiver. + + This class illustrates a minimal implementation of a finite dimensional + algebra with basis. + """ + + def __init__(self, R): + r""" + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: TestSuite(A).run() + + """ + basis_keys = ['x', 'y', 'a', 'b'] + self._nonzero_products = { + 'xx':'x', 'xa':'a', 'xb':'b', + 'yy':'y', 'ay':'a', 'by':'b' + } + + CombinatorialFreeModule.__init__(self, R, basis_keys, category = FiniteDimensionalAlgebrasWithBasis(R)) + + def _repr_(self): + r""" + EXAMPLES:: + + sage: FiniteDimensionalAlgebrasWithBasis(QQ).example() # indirect doctest + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + """ + return "An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over %s "%(self.base_ring()) + + def one(self): + r""" + Returns the multiplicative identity element of the algebra, as per :meth:`AlgebrasWithBasis.ParentMethods.one_basis`. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.one() + x + y + """ + return self.sum_of_monomials(['x', 'y']) + + def product_on_basis(self, w1, w2): + r""" + Product of basis elements, as per :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + + Here is the multiplication table for the algebra:: + + sage: matrix([[p*q for q in A.basis()] for p in A.basis()]) + [x 0 a b] + [0 y 0 0] + [0 a 0 0] + [0 b 0 0] + + Here we take some products of linear combinations of basis elements:: + + sage: x, y, a, b = A.basis() + sage: a * (1-b)^2 * x + 0 + sage: x*a + b*y + a + b + sage: x*x + x + sage: x*y + 0 + sage: x*a*y + a + """ + if w1+w2 in self._nonzero_products: + return self.monomial(self._nonzero_products[w1+w2]) + else: + return self.zero() + + @cached_method + def algebra_generators(self): + r""" + Returns the generators of this algebra, as per :meth:`Algebras.ParentMethods.algebra_generators`. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: A.algebra_generators() + Finite family {'y': y, 'x': x, 'b': b, 'a': a} + """ + return self.basis() + + def _repr_term(self, p): + r""" + This method customizes the string representation of the basis element indexed by ``p``. + + In this example, we just return the string representation of ``p`` itself. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.one() + x + y + """ + return str(p) + +Example = KroneckerQuiverPathAlgebra + diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fba4969a297..87dee12b19b 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -2,14 +2,20 @@ Finite dimensional algebras with basis """ #***************************************************************************** -# Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) -# 2011 Nicolas M. Thiery +# Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) +# 2011-2014 Nicolas M. Thiery +# 2011-2014 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #****************************************************************************** +import operator +from sage.misc.cachefunc import cached_method, cached_function from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.non_unital_algebras import NonUnitalAlgebras +from sage.categories.algebras import Algebras +from sage.categories.semisimple_algebras import SemisimpleAlgebras class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ @@ -22,6 +28,10 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: C.super_categories() [Category of algebras with basis over Rational Field, Category of finite dimensional modules with basis over Rational Field] + sage: C.example() + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field TESTS:: @@ -32,33 +42,323 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): True """ + def example(self): # TODO: really needed? + """ + Return an example of a finite dimensional algebra with basis. + + .. SEEALSO:: :meth:`Category.example`. + + EXAMPLES:: + + sage: FiniteDimensionalAlgebrasWithBasis(QQ).example() + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + """ + from sage.categories.examples.finite_dimensional_algebras_with_basis import Example + return Example(self.base_ring()) + class ParentMethods: - pass + + @cached_method + def radical_basis(self, cache_products=True): + r""" + Return a basis of the Jacobson radical of the algebra. + + .. NOTE:: + + This implementation also works for algebras over fields of + finite characteristic `p` in which we can compute `x^{1/p}`. + + INPUT: + + - ``cache_products`` -- boolean (default: ``True``); if ``True`` + then all products computed in this method are cached. + + OUTPUT: + + - ``list`` of elements of ``self`` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field + sage: A.radical_basis() + [a, b] + + We construct the group algebra of the Klein Four-Group over the rationals:: + + sage: A = KleinFourGroup().algebra(QQ) + + This algebra belongs to the category of finite dimensional + algebras over the rationals:: + + sage: A in FiniteDimensionalAlgebrasWithBasis(QQ) + True + + Since the field has characteristic `0`, Maschke's Theorem + tells us that the group algebra is semisimple. So its + radical is the zero ideal:: + + sage: A.radical_basis() + [] + + Let's work instead over a field of characteristic `2`:: + + sage: A = KleinFourGroup().algebra(GF(2)) + sage: A.radical_basis() + [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] + + TESTS:: + + sage: A = KleinFourGroup().algebra(GF(2)) + sage: A.radical_basis(cache_products=True) + [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] + sage: A.radical_basis(cache_products=False) + [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] + + :: + + sage: A = KleinFourGroup().algebra(QQ) + sage: A.radical_basis(cache_products=True) + [] + sage: A.radical_basis(cache_products=False) + [] + + .. TODO:: explain and check this example:: + + :: + + sage: class AnAlgebra(CombinatorialFreeModule): + ... def __init__(self, F): + ... R. = PolynomialRing(F) + ... I = R.ideal(x**F.characteristic()-F.one()) + ... self._xbar = R.quotient(I).gen() + ... basis_keys = [self._xbar**i for i in range(F.characteristic())] + ... CombinatorialFreeModule.__init__(self, F, basis_keys, + ... category = FiniteDimensionalAlgebrasWithBasis(F)) + ... def one(self): + ... return self.basis()[self.base_ring().one()] + ... def product_on_basis(self, w1, w2): + ... return self.from_vector(vector(w1*w2)) + sage: AnAlgebra(GF(3)).radical_basis() + [B[1] + 2*B[xbar^2], B[xbar] + 2*B[xbar^2]] + sage: AnAlgebra(GF(16,'a')).radical_basis() + [B[1] + B[xbar]] + sage: AnAlgebra(GF(49,'a')).radical_basis() + [B[1] + 6*B[xbar^6], B[xbar] + 6*B[xbar^6], B[xbar^2] + 6*B[xbar^6], B[xbar^3] + 6*B[xbar^6], B[xbar^4] + 6*B[xbar^6], B[xbar^5] + 6*B[xbar^6]] + + .. SEEALSO:: :meth:`radical`, :class:`SemisimpleAlgebras` + + AUTHORS: TODO: polish this! + + - Franco Saliola + """ + F = self.base_ring() + if not F.is_field(): + raise NotImplementedError, "the base ring must be a field" + p = F.characteristic() + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + + if cache_products is True: + product_on_basis = cached_function(self.product_on_basis) + else: + product_on_basis = self.product_on_basis + + if p == 0: + keys = self.basis().keys() + mat = matrix(self.base_ring(), [ + [sum(product_on_basis(x,j).coefficient(i) * product_on_basis(y,i).coefficient(j) + for i in keys for j in keys) for x in keys] for y in keys + ]) + rad_basis = mat.kernel().basis() + else: + # TODO: some finite field elements in Sage have both an + # ``nth_root`` method and a ``pth_root`` method (such as ``GF(9,'a')``), + # some only have a ``nth_root`` element such as ``GF(2)`` + # I imagine that ``pth_root`` would be fastest, but it is not + # always available.... + if hasattr(self.base_ring().one(), 'nth_root'): + root_fcn = lambda s, x : x.nth_root(s) + else: + root_fcn = lambda s, x : x**(1/s) + + s, n = 1, self.dimension() + B = [b.on_left_matrix() for b in self.basis()] + I = B[0].parent().one() + while s <= n: + BB = B + [I] + G = matrix([ [(-1)**s * (b*bb).characteristic_polynomial()[n-s] + for bb in BB] for b in B]) + C = G.left_kernel().basis() + if 1 < s < F.order(): + C = [vector(F, [root_fcn(s, ci) for ci in c]) for c in C] + B = [ sum(ci*b for (ci,b) in zip(c,B)) for c in C ] + s = p * s + e = vector(self.one()) + rad_basis = [b*e for b in B] + + return [self.from_vector(vec) for vec in rad_basis] + + @cached_method + def radical(self): + r""" + Return the Jacobson radical of ``self``. + + .. SEEALSO:: :meth:`radical_basis`, :meth:`semisimple_quotient` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: radical = A.radical(); radical + A subobject of An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field + sage: radical in Modules(QQ).WithBasis().FiniteDimensional() + True + sage: radical in Semigroups() + True + sage: radical.dimension() + 2 + sage: radical.basis() + Finite family {0: B[0], 1: B[1]} + sage: radical.ambient() is A + True + sage: [c.lift() for c in radical.basis()] + [a, b] + + .. TODO:: + + - this is in fact an ideal. + - add refs + + TESTS:: + + sage: TestSuite(radical).run() + """ + category = NonUnitalAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() + return self.submodule(self.radical_basis(), + category = category, + already_echelonized = True) + + @cached_method + def semisimple_quotient(self): + """ + Return the semisimple quotient of ``self``. + + This is the quotient of ``self`` by its radical. + + .. SEEALSO:: :meth:`radical` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: a,b,x,y = sorted(A.basis()) + sage: S = A.semisimple_quotient(); S + Free module generated by {'x', 'y'} over Rational Field + sage: S in SemisimpleAlgebras + True + sage: S.basis() + Finite family {'y': B['y'], 'x': B['x']} + sage: xs,ys = sorted(S.basis()) + sage: (xs + ys) * xs + B['x'] + + .. TODO:: + + This example is not very interesting, because the + semisimple quotient is actually a subalgebra. + + TESTS:: + + sage: TestSuite(S).run() + """ + ring = self.base_ring() + category=Algebras(ring).WithBasis().FiniteDimensional().Quotients() \ + & SemisimpleAlgebras(ring) + return self.quotient(self.radical(), category=category) + + + @cached_method + def center_basis(self): + r""" + Return a basis of the center of ``self``. + + OUTPUT: + + - ``list`` of elements of ``self`` + + .. SEEALSO:: :meth:`center` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: A.center_basis() + [x + y] + + """ + return self.annihilator_basis(self.algebra_generators(), self.bracket) + + @cached_method + def center(self): + r""" + Return the center of ``self``. + + .. SEEALSO:: :meth:`center_basis` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: center = A.center(); center + A subobject of An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: center in Algebras(QQ).WithBasis().FiniteDimensional().Commutative() + True + sage: center.dimension() + 1 + sage: center.basis() + Finite family {0: B[0]} + sage: center.ambient() is A + True + sage: [c.lift() for c in center.basis()] + [x + y] + + TESTS:: + + sage: TestSuite(center).run() + """ + category = FiniteDimensionalAlgebrasWithBasis(self.base_ring()).Subobjects().Commutative() + return self.submodule(self.center_basis(), + category = category, + already_echelonized = True) class ElementMethods: - def on_left_matrix(self, new_BR = None): + def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ - Returns the matrix of the action of self on the algebra my - multiplication on the left + Returns the matrix of the action of self on the algebra. - If new_BR is specified, then the matrix will be over new_BR. + INPUT:: - TODO: split into to parts - - build the endomorphism of multiplication on the left - - build the matrix of an endomorphism + - ``base_ring`` -- a ring, constructs the matrix over ``base_ring`` + - ``action`` -- a function (default: :func:`operator.mul`) + - ``side`` -- 'left' or 'right' (default: 'right') EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ, 3) sage: a = QS3([2,1,3]) - sage: a.on_left_matrix() + sage: a.to_matrix(side='left') [0 0 1 0 0 0] [0 0 0 0 1 0] [1 0 0 0 0 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [0 0 0 1 0 0] - sage: a.on_left_matrix(RDF) + sage: a.to_matrix(base_ring=RDF, side="left") [0.0 0.0 1.0 0.0 0.0 0.0] [0.0 0.0 0.0 0.0 1.0 0.0] [1.0 0.0 0.0 0.0 0.0 0.0] @@ -66,23 +366,16 @@ def on_left_matrix(self, new_BR = None): [0.0 1.0 0.0 0.0 0.0 0.0] [0.0 0.0 0.0 1.0 0.0 0.0] - AUTHOR: Mike Hansen + AUTHORS: Mike Hansen # TODO: polish this! """ - parent = self.parent() - - if parent.get_order() is None: - cc = parent._combinatorial_class + basis = self.parent().basis() + action_left = action + if side == 'right': + action = lambda x: action_left(basis[x], self) else: - cc = parent.get_order() - - BR = parent.base_ring() - if new_BR is None: - new_BR = BR - - from sage.matrix.all import MatrixSpace - MS = MatrixSpace(new_BR, parent.dimension(), parent.dimension()) - l = [ (self*parent(m)).to_vector() for m in cc ] - return MS(l).transpose() + action = lambda x: action_left(self, basis[x]) + endo = self.parent().module_morphism(on_basis=action, codomain=self.parent()) + return endo.matrix(base_ring=base_ring) - _matrix_ = on_left_matrix # For temporary backward compatibility - to_matrix = on_left_matrix + _matrix_ = to_matrix # For temporary backward compatibility + on_left_matrix = to_matrix diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 53d7de52c6a..d954d28a393 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -9,6 +9,8 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +import operator +from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring class FiniteDimensionalModulesWithBasis(CategoryWithAxiom_over_base_ring): @@ -31,7 +33,166 @@ class FiniteDimensionalModulesWithBasis(CategoryWithAxiom_over_base_ring): """ class ParentMethods: - pass + + @cached_method + def vectors_parent(self): + """ + Returns the parent of the vectors created with + ``x.to_vector()``. + + EXAMPES:: + + sage: F = Modules(QQ).WithBasis().example() + sage: F.vectors_parent() + + """ + return self.zero().to_vector().parent() + + def span(self, gens, check = True, already_echelonized = False): + return self.vectors_parent().span( + [g.to_vector() for g in gens], + check=check, + already_echelonized = already_echelonized) + + def annihilator(self, S, action=operator.mul, side='right', category=None): + r""" + INPUT: + - ``S`` -- a finite set of objects + - ``side`` -- 'left' or 'right' (default: 'right') + + - ``action`` -- a function (default: `operator.mul`) + + Assumptions: ``action`` takes elements of ``self`` as + first argument, and elements of ``S`` as second + argument, and is linear on its first argument + (typically it is bilinear). + + Returns the supspace of the elements `x` of ``self`` + such that `action(x,s) = 0` for all `s\in S`. + + If ``side`` is 'left', then the order of the arguments + of ``action`` is reversed. + + TODO: double check the convention for ``left/right``. + + .. seealso:: :meth:`annihilator_basis` for lots of examples. + + EXAMPLES:: + + sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: x,y,a,b = F.basis() + sage: A = F.annihilator([a + 3*b + 2*y]); A + Vector space of degree 4 and dimension 1 over Rational Field + Basis matrix: + [ 1 0 -1/2 -3/2] + + Note: currently `A` forgot everything about `F`; its + ambient space is a :class:`FreeModule` of same dimension + as `F`. But one can, for example, compute inclusions:: + + sage: A = F.annihilator([]); A .rename("A") + sage: Ax = F.annihilator([x]); Ax .rename("Ax") + sage: Ay = F.annihilator([y]); Ay .rename("Ay") + sage: Axy = F.annihilator([x,y]); Axy.rename("Axy") + sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_subspace"))) + sage: P.cover_relations() + [[Axy, Ay], [Axy, Ax], [Ay, A], [Ax, A]] + + """ + return self.span(self.annihilator_basis(S, action, side), already_echelonized=True) + + def annihilator_basis(self, S, action=operator.mul, side='right'): + """ + + EXAMPLES: + + By default, the action is the standard `*` + operation. So our first example is about an algebra:: + + sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F + An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + sage: x,y,a,b = F.basis() + + In this algebra, multiplication on the right by `x` + kills all basis elements but `x`:: + + sage: x*x, y*x, a*x, b*x + (x, 0, 0, 0) + + So the annihilator is the subspace spanned by + `y`,`a`,and `b`:: + + sage: F.annihilator_basis([x]) + [y, a, b] + + The same holds for `a` and `b`:: + + sage: x*a, y*a, a*a, b*a + (a, 0, 0, 0) + sage: F.annihilator_basis([a]) + [y, a, b] + + On the other hand, `y` kills only `x`:: + + sage: F.annihilator_basis([y]) + [x] + + Here is a non trivial annihilator:: + + sage: F.annihilator_basis([a + 3*b + 2*y]) + [-1/2*a - 3/2*b + x] + + Let's check it:: + + sage: (-1/2*a - 3/2*b + x) * (a + 3*b + 2*y) + 0 + + Doing the same calculations on the left exchanges the + roles of `x` and `y`:: + + sage: F.annihilator_basis([y], side="left") + [x, a, b] + sage: F.annihilator_basis([a], side="left") + [x, a, b] + sage: F.annihilator_basis([b], side="left") + [x, a, b] + sage: F.annihilator_basis([x], side="left") + [y] + sage: F.annihilator_basis([a+3*b+2*x], side="left") + [-1/2*a - 3/2*b + y] + + By specifying an inner product, this method can be + used to compute the orthogonal of a subspace (TODO: + add an example). + + By specifying instead the standard Lie bracket as + action, one can compute the commutator of a subspace + of `F`:: + + sage: F.annihilator_basis([a+b], action = F.bracket) + [x + y, a, b] + + In particular one can computer the center of the + algebra. In our example, it is reduced to the + identity:: + + sage: F.annihilator_basis(F.algebra_generators(), action = F.bracket) + [x + y] + + .. seealso:: :meth:`FiniteAlgebrasWithBasis.ParentMethods.center_basis`. + """ + # TODO: optimize this! + from sage.matrix.constructor import matrix + if side == 'right': + action_left = action + action = lambda b,s: action_left(s, b) + + mat = matrix(self.base_ring(), self.dimension(), 0) + for s in S: + mat = mat.augment(matrix(self.base_ring(), + [action(s,b).to_vector() for b in self.basis()])) + return map(self.from_vector, mat.left_kernel().basis()) class ElementMethods: pass diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 1110837b518..a2a33dac02c 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -444,6 +444,135 @@ def _repr_(self): name = "Free module generated by {}".format(self.basis().keys()) return name + " over {}".format(self.base_ring()) + def echelonize(self, gens): + """ + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: X.echelonize([x[0]-x[1], x[0]-x[2],x[1]-x[2]]) + [x[0] - x[2], x[1] - x[2]] + """ + from sage.matrix.constructor import matrix + mat = matrix([g.to_vector() for g in gens]) + return [self.from_vector(v) for v in mat.row_space().basis()] + + + + def submodule(self, gens, check = False, already_echelonized=False, category=None): + r""" + Construct the `R`-sub free module spanned by ``gens`` + + INPUT: + - ``gens`` -- a list or family of elements of ``self`` + - ``check`` -- (default: True) whether to verify that the + elements of ``gens`` are in ``self``. + - ``already_echelonized`` -- (default: False) whether the + elements of gens are already in (not necessarily reduced) + echelon form. + + If ``already_echelonized`` is False, then the generators + are put in reduced echelon form using :meth:`echelonize`, + and reindexed by `0,1,...`. + + .. warning:: at this point, this method only works for + finite dimensional submodules. + + The basis of the submodule uses the same index set as the + generators, and the lifting map sends `y_i` to `gens[i]`. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: Y = X.submodule([x[0]-x[1], x[1]-x[2]], already_echelonized = True) + sage: Y.print_options(prefix='y'); Y + Free module generated by {0, 1} over Rational Field + sage: y = Y.basis() + sage: y[1] + y[1] + sage: y[1].lift() + x[1] - x[2] + sage: Y.retract(x[0]-x[2]) + y[0] + y[1] + sage: Y.retract(x[0]) + Traceback (most recent call last): + ... + ValueError: x[0] is not in the image of Generic morphism: + From: Free module generated by {0, 1} over Rational Field + To: Free module generated by {0, 1, 2} over Rational Field + + We now implement by hand the center of the algebra of the + symmetric group `S_3`:: + + sage: S3 = SymmetricGroup(3) + sage: S3A = S3.algebra(QQ) + sage: basis = S3A.annihilator_basis(S3A.algebra_generators(), S3A.bracket) + sage: basis + [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] + sage: center = S3A.submodule(basis, + ... category = AlgebrasWithBasis(QQ).Subobjects(), + ... already_echelonized = True) + sage: center + A subobject of Group algebra of Symmetric group of order 3! as a permutation group over Rational Field + sage: center in Algebras + True + sage: center.print_options(prefix='c') + sage: c = center.basis() + sage: c[1].lift() + B[(2,3)] + B[(1,2)] + B[(1,3)] + sage: c[0]^2 + c[0] + sage: e = 1/6*(c[0]+c[1]+c[2]) + sage: e.is_idempotent() + True + + Of course, the center is best constructed using:: + + sage: center = S3A.center() + + TESTS:: + + sage: TestSuite(Y).run() + sage: TestSuite(center).run() + """ + if not already_echelonized: + gens = self.echelonize(gens) + from sage.modules.subquotient_module_with_basis import SubModuleWithBasis + return SubModuleWithBasis(gens, ambient=self, category = category) + + def quotient(self, submodule, check = False, already_echelonized=False, category=None): + r""" + Construct the quotient free module ``self``/``submodule`` + + INPUT: + + - ``submodule`` -- a free submodule of ``self``, or something that can + be turned into one via self.submodule(submodule). + - ``check``, ``already_echelonized`` -- passed down to :meth:`submodule`, which see + + .. note:: At this point, only free quotients are implemented + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: Y = X.quotient([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] + """ + from sage.modules.subquotient_module_with_basis import SubModuleWithBasis, QuotientModuleWithBasis + if not isinstance(submodule, SubModuleWithBasis): + submodule = self.submodule(submodule, check=check, already_echelonized = already_echelonized) + return QuotientModuleWithBasis(submodule, category = category) def tensor(*parents): """ diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py new file mode 100644 index 00000000000..7c142037aa5 --- /dev/null +++ b/src/sage/categories/semisimple_algebras.py @@ -0,0 +1,55 @@ +r""" +Semisimple Algebras +""" +#***************************************************************************** +# Copyright (C) 2011 Nicolas M. Thiery +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from category_types import Category_over_base_ring +from algebras import Algebras +from sage.misc.cachefunc import cached_method + + +class SemisimpleAlgebras(Category_over_base_ring): + """ + The category of semisimple algebras over a given base ring. + + EXAMPLES:: + + sage: SemisimpleAlgebras(QQ) + Category of semisimple algebras over Rational Field + sage: SemisimpleAlgebras(QQ).super_categories() + [Category of algebras over Rational Field] + + Typically, finite group algebras are semisimple:: + + sage: DihedralGroup(5).algebra(QQ) in SemisimpleAlgebras + True + + Unless the characteristic of the field divides the order of the group:: + + sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras + False + + sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras # todo: not implemented + True + + .. seealso:: ``_ + + TESTS:: + + sage: TestSuite(SemisimpleAlgebras(QQ)).run() + """ + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: SemisimpleAlgebras(QQ).super_categories() + [Category of algebras over Rational Field] + """ + R = self.base_ring() + return [Algebras(R)] diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index ef8092d07f9..86bb16a5d13 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1631,6 +1631,12 @@ def set_order(self, order): the one used in the generation of the elements of self's associated enumerated set. + .. warning:: many cached methods depend on this order, in + particular for constructing subspaces and + quotients. Changing the order after computing such does + currently not invalidate those cache, and is likely to + bring in inconsistencies. + EXAMPLES:: sage: QS2 = SymmetricGroupAlgebra(QQ,2) @@ -1641,6 +1647,8 @@ def set_order(self, order): [[2, 1], [1, 2]] """ self._order = order + from sage.combinat.ranker import rank_from_list + self._rank_basis = rank_from_list(self._order) @cached_method def get_order(self): @@ -1654,9 +1662,32 @@ def get_order(self): [[2, 1], [1, 2]] """ if self._order is None: - self._order = list(self.basis().keys()) + self.set_order(self.basis().keys().list()) return self._order + def get_order_cmp(self): + """ + Returns a comparison function on the basis indices which is + compatible with the current term order. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: Acmp = A.get_order_cmp() + sage: sorted(A.basis().keys(), Acmp) + ['x', 'y', 'a', 'b'] + sage: A.set_order(list(reversed(A.basis().keys()))) + sage: Acmp = A.get_order_cmp() + sage: sorted(A.basis().keys(), Acmp) + ['b', 'a', 'y', 'x'] + """ + self.get_order() + return self._order_cmp + + def _order_cmp(self, x, y): + return cmp( self._rank_basis(x), self._rank_basis(y) ) + + @cached_method def _dense_free_module(self, base_ring=None): """ @@ -2359,6 +2390,45 @@ def _from_dict( self, d, coerce=False, remove_zeros=True ): d = dict( (key, coeff) for key, coeff in d.iteritems() if coeff) return self.element_class( self, d ) + def echelon_form(self, elements, base_ring=None): + r""" + Compute the echelon form of the given elements. + + INPUT: + + - ``elements`` - a list of elements of ``self``. + + - ``base_ring`` - ring (default: ``None``): compute the echelon + form over the given ring; if ``base_ring`` is ``None``, then uses + the base ring of ``self``. + + OUTPUT: + + - list of elements of ``self`` + + EXAMPLES:: + + 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.echelon_form(elements, base_ring=QQ) + [B[1] - 17*B[2] + B[4], B[3] - 1/6*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']] + """ + from sage.matrix.constructor import matrix + if base_ring is None: + base_ring = self.base_ring() + mat = matrix(base_ring, map(vector,elements)) + mat.echelonize() + return [self.from_vector(vec) for vec in mat if vec != 0] class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py new file mode 100644 index 00000000000..0da4ce1a6ca --- /dev/null +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -0,0 +1,207 @@ +r""" +Quotients of Modules With Basis + +sage: H = IwahoriHeckeAlgebraT("A2", QQ(0)) +sage: C = H.submodule(H.center_basis(), H, category=FiniteDimensionalAlgebrasWithBasis(QQ).Subquotients()) +sage: TestSuite(C).run() + +""" +#***************************************************************************** +# Copyright (C) 2010 Florent Hivert +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.sets.family import Family +from sage.combinat.free_module import CombinatorialFreeModule +from sage.misc.lazy_attribute import lazy_attribute +from sage.categories.all import ModulesWithBasis + +class QuotientModuleWithBasis(CombinatorialFreeModule): + r""" + """ + @staticmethod + def __classcall_private__(cls, submodule, category = None): + r""" + Normalize the input + + TESTS:: + + """ + category = ModulesWithBasis(submodule.base_ring()).Quotients().or_subcategory(category, join=True) + return super(QuotientModuleWithBasis, cls).__classcall__( + cls, submodule, category) + + def __init__(self, submodule, category): + r""" + TESTS:: + + sage: from sage.modules.subquotient_module_with_basis import QuotientModuleWithBasis + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) + sage: Y = QuotientModuleWithBasis(I) + sage: Y + Free module generated by {2} over Rational Field + sage: Y.category() + Join of Category of vector spaces with basis over Rational Field and Category of quotients of sets + sage: Y.basis().list() + [B[2]] + sage: TestSuite(Y).run() + """ + self._submodule = submodule + self._ambient = submodule.ambient() + embedding = submodule.lift + # Morphism that computes normal forms module submodule + self._normal = embedding.cokernel_projection() + # FIXME: The following currently works only if: + # - The ambient space is finite dimensional + # - The embedding is triangular + indices = embedding.cokernel_basis_indices() + CombinatorialFreeModule.__init__(self, + submodule.base_ring(), indices, + category = category) + + def ambient(self): + r""" + Returns the ambient space of ``self`` + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() + sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])) + sage: Y.ambient() is X + True + """ + return self._ambient + + def lift(self, x): + """ + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() + sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: Y.lift(y[2]) + x[2] + """ + assert x in self + return self.ambient()._from_dict(x._monomial_coefficients) + + def retract(self, x): + r""" + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() + sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: Y.print_options(prefix='y') + sage: Y.retract(x[0]) + y[2] + sage: Y.retract(x[1]) + y[2] + sage: Y.retract(x[2]) + y[2] + """ + return self._from_dict(self._normal(x)._monomial_coefficients) + + +class SubModuleWithBasis(CombinatorialFreeModule): + r""" + A base class for submodules of a ModuleWithBasis spanned by a + (possibly infinite) basis in echelon form. + """ + + @staticmethod + def __classcall_private__(cls, basis, ambient = None, category = None, *args, **opts): + r""" + Normalize the input + + TESTS:: + + sage: from sage.modules.subquotient_module_with_basis 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 is Y2 + True + """ + basis = Family(basis) + if ambient is None: + ambient = basis.an_element().parent() + category = ModulesWithBasis(ambient.base_ring()).Subobjects().or_subcategory(category, join=True) + return super(SubModuleWithBasis, cls).__classcall__( + cls, basis, ambient, category, *args, **opts) + + def __init__(self, basis, ambient, category): + r""" + TESTS:: + + sage: from sage.modules.subquotient_module_with_basis import SubModuleWithBasis + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: ybas = (x[0]-x[1], x[1]-x[2]) + sage: Y = SubModuleWithBasis(ybas, X) + sage: Y.basis().list() + [B[0], B[1]] + sage: [ y.lift() for y in Y.basis() ] + [B[0] - B[1], B[1] - B[2]] + sage: TestSuite(Y).run() + """ + import operator + ring = ambient.base_ring() + CombinatorialFreeModule.__init__(self, ring, basis.keys(), category = category) + self._ambient = ambient + self._basis = basis + self.lift_on_basis = self._basis.__getitem__ + + def _inverse_on_support(self, j): + return self._invsup.get(j, None) + + def ambient(self): + """ + Returns the ambient space of ``self`` + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: Y = X.submodule((x[0]-x[1], x[1]-x[2])) + sage: Y.ambient() is X + True + """ + return self._ambient + + @lazy_attribute + def lift(self): + r""" + Returns the lift map to the ambient space. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() + sage: [ u.lift() for u in y ] + [B[0] - B[1], B[1] - B[2]] + sage: (y[0] + y[1]).lift() + B[0] - B[2] + """ + return self.module_morphism(self.lift_on_basis, + codomain=self.ambient(), + triangular="lower", cmp = self.ambient().get_order_cmp(), + inverse_on_support="compute") + + @lazy_attribute + def retract(self): + r""" + Returns the retract map from the ambient space. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() + sage: Y.retract(x[0] - x[2]) + B[0] + B[1] + + TESTS:: + + sage: all( Y.retract(u.lift()) == u for u in y ) + True + """ + return self.lift.section() From 2a9ccb0b90e235dc305c1ad5bc761208de00739d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 2 Jul 2014 18:29:40 -0500 Subject: [PATCH 016/665] 11111: fixed Sage startup (NonUnitalAlgebras had to be rebased to NonAssociativeAlgebras) --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 87dee12b19b..cb455ea13d5 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -13,8 +13,8 @@ import operator from sage.misc.cachefunc import cached_method, cached_function from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.non_unital_algebras import NonUnitalAlgebras from sage.categories.algebras import Algebras +from sage.categories.associative_algebras import AssociativeAlgebras from sage.categories.semisimple_algebras import SemisimpleAlgebras class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): @@ -238,7 +238,7 @@ def radical(self): sage: TestSuite(radical).run() """ - category = NonUnitalAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() + category = AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() return self.submodule(self.radical_basis(), category = category, already_echelonized = True) From bac267e5c4558b56271e9f5bd24d8e514776b5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 2 Jul 2014 19:50:24 -0500 Subject: [PATCH 017/665] 11111: fixed some remaining rebasing issues (most tests pass now) + proofreading --- .../finite_dimensional_algebras_with_basis.py | 19 +++-- .../finite_dimensional_algebras_with_basis.py | 85 ++++++++++--------- .../finite_dimensional_modules_with_basis.py | 9 +- src/sage/categories/modules_with_basis.py | 11 +-- src/sage/categories/rings.py | 2 +- src/sage/combinat/free_module.py | 2 + .../modules/subquotient_module_with_basis.py | 13 +-- 7 files changed, 76 insertions(+), 65 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py index 6eca38c288d..0303e44e0dd 100644 --- a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -2,7 +2,7 @@ Examples of finite dimensional algebras with basis """ #***************************************************************************** -# Copyright (C) 2008-2009 Franco Saliola +# Copyright (C) 2008-2014 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -21,14 +21,13 @@ class KroneckerQuiverPathAlgebra(CombinatorialFreeModule): algebra with basis. """ - def __init__(self, R): + def __init__(self, base_ring): r""" EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: TestSuite(A).run() - """ basis_keys = ['x', 'y', 'a', 'b'] self._nonzero_products = { @@ -36,7 +35,7 @@ def __init__(self, R): 'yy':'y', 'ay':'a', 'by':'b' } - CombinatorialFreeModule.__init__(self, R, basis_keys, category = FiniteDimensionalAlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, category = FiniteDimensionalAlgebrasWithBasis(base_ring)) def _repr_(self): r""" @@ -49,7 +48,9 @@ def _repr_(self): def one(self): r""" - Returns the multiplicative identity element of the algebra, as per :meth:`AlgebrasWithBasis.ParentMethods.one_basis`. + Return the unit of this algebra. + + .. SEEALSO:: :meth:`AlgebrasWithBasis.ParentMethods.one_basis` EXAMPLES:: @@ -61,7 +62,9 @@ def one(self): def product_on_basis(self, w1, w2): r""" - Product of basis elements, as per :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. + Return the product of the two basis elements indexed by ``w1`` and ``w2``. + + .. SEEALSO:: :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. EXAMPLES:: @@ -97,7 +100,9 @@ def product_on_basis(self, w1, w2): @cached_method def algebra_generators(self): r""" - Returns the generators of this algebra, as per :meth:`Algebras.ParentMethods.algebra_generators`. + Return the generators of this algebra. + + .. SEEALSO:: :meth:`Algebras.ParentMethods.algebra_generators`. EXAMPLES:: diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index cb455ea13d5..fb838af8908 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -18,7 +18,7 @@ from sage.categories.semisimple_algebras import SemisimpleAlgebras class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): - """ + r""" The category of finite dimensional algebras with a distinguished basis. EXAMPLES:: @@ -42,26 +42,12 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): True """ - def example(self): # TODO: really needed? - """ - Return an example of a finite dimensional algebra with basis. - - .. SEEALSO:: :meth:`Category.example`. - - EXAMPLES:: - - sage: FiniteDimensionalAlgebrasWithBasis(QQ).example() - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - """ - from sage.categories.examples.finite_dimensional_algebras_with_basis import Example - return Example(self.base_ring()) - class ParentMethods: @cached_method def radical_basis(self, cache_products=True): r""" - Return a basis of the Jacobson radical of the algebra. + Return a basis of the Jacobson radical of this algebra. .. NOTE:: @@ -211,14 +197,15 @@ def radical(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: radical = A.radical(); radical - A subobject of An example of a finite dimensional algebra with basis: + Radical of An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: radical in Modules(QQ).WithBasis().FiniteDimensional() - True - sage: radical in Semigroups() + sage: from sage.categories.associative_algebras import AssociativeAlgebras + sage: radical in AssociativeAlgebras(QQ).WithBasis().FiniteDimensional() True sage: radical.dimension() 2 @@ -231,17 +218,21 @@ def radical(self): .. TODO:: - - this is in fact an ideal. - - add refs + - This is in fact an ideal. + - Add references + - Pickling by construction, as ``A.center()`` + - Lazy evaluation of ``_repr_`` TESTS:: sage: TestSuite(radical).run() """ category = AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() - return self.submodule(self.radical_basis(), - category = category, - already_echelonized = True) + radical = self.submodule(self.radical_basis(), + category = category, + already_echelonized = True) + radical.rename("Radical of {}".format(self)) + return radical @cached_method def semisimple_quotient(self): @@ -258,7 +249,9 @@ def semisimple_quotient(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: a,b,x,y = sorted(A.basis()) sage: S = A.semisimple_quotient(); S - Free module generated by {'x', 'y'} over Rational Field + Semisimple quotient of An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: S in SemisimpleAlgebras True sage: S.basis() @@ -269,8 +262,10 @@ def semisimple_quotient(self): .. TODO:: - This example is not very interesting, because the - semisimple quotient is actually a subalgebra. + - This example is not very interesting because the + semisimple quotient is actually a subalgebra. + - Pickling by construction, as ``A.center()`` + - Lazy evaluation of ``_repr_`` TESTS:: @@ -279,7 +274,9 @@ def semisimple_quotient(self): ring = self.base_ring() category=Algebras(ring).WithBasis().FiniteDimensional().Quotients() \ & SemisimpleAlgebras(ring) - return self.quotient(self.radical(), category=category) + result = self.quotient(self.radical(), category=category) + result.rename("Semisimple quotient of {}".format(self)) + return result @cached_method @@ -299,7 +296,6 @@ def center_basis(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.center_basis() [x + y] - """ return self.annihilator_basis(self.algebra_generators(), self.bracket) @@ -313,9 +309,13 @@ def center(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: center = A.center(); center - A subobject of An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + Center of An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: center in Algebras(QQ).WithBasis().FiniteDimensional().Commutative() True sage: center.dimension() @@ -327,23 +327,30 @@ def center(self): sage: [c.lift() for c in center.basis()] [x + y] + .. TODO:: + + - Pickling by construction, as ``A.center()`` + - Lazy evaluation of ``_repr_`` + TESTS:: sage: TestSuite(center).run() """ - category = FiniteDimensionalAlgebrasWithBasis(self.base_ring()).Subobjects().Commutative() - return self.submodule(self.center_basis(), - category = category, - already_echelonized = True) + category = Algebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() + center = self.submodule(self.center_basis(), + category = category, + already_echelonized = True) + center.rename("Center of {}".format(self)) + return center class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ - Returns the matrix of the action of self on the algebra. + Return the matrix of the action of ``self`` on the algebra. INPUT:: - - ``base_ring`` -- a ring, constructs the matrix over ``base_ring`` + - ``base_ring`` -- the base ring for the matrix to be constructed - ``action`` -- a function (default: :func:`operator.mul`) - ``side`` -- 'left' or 'right' (default: 'right') diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index d954d28a393..f30db4dcfa5 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -37,14 +37,13 @@ class ParentMethods: @cached_method def vectors_parent(self): """ - Returns the parent of the vectors created with - ``x.to_vector()``. + Return the parent of the vectors created with ``x.to_vector()``. - EXAMPES:: + EXAMPLES:: - sage: F = Modules(QQ).WithBasis().example() + sage: F = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: F.vectors_parent() - + Vector space of dimension 4 over Rational Field """ return self.zero().to_vector().parent() diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index a2a33dac02c..632eae43141 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -458,14 +458,13 @@ def echelonize(self, gens): mat = matrix([g.to_vector() for g in gens]) return [self.from_vector(v) for v in mat.row_space().basis()] - - def submodule(self, gens, check = False, already_echelonized=False, category=None): r""" - Construct the `R`-sub free module spanned by ``gens`` + Construct the `R`-sub free module spanned by ``gens``. INPUT: - - ``gens`` -- a list or family of elements of ``self`` + + - ``gens`` -- a list or family of elements of ``self`` - ``check`` -- (default: True) whether to verify that the elements of ``gens`` are in ``self``. - ``already_echelonized`` -- (default: False) whether the @@ -499,9 +498,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: Y.retract(x[0]) Traceback (most recent call last): ... - ValueError: x[0] is not in the image of Generic morphism: - From: Free module generated by {0, 1} over Rational Field - To: Free module generated by {0, 1, 2} over Rational Field + ValueError: x[0] is not in the image We now implement by hand the center of the algebra of the symmetric group `S_3`:: diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 0231901b8c4..8ab5f522534 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -610,7 +610,7 @@ def quo(self, I, names=None): NOTE: - This is a synonyme for :meth:`quotient`. + This is a synonym for :meth:`quotient`. EXAMPLE:: diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 86bb16a5d13..f081ef0eb88 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -2430,6 +2430,8 @@ def echelon_form(self, elements, base_ring=None): mat.echelonize() return [self.from_vector(vec) for vec in mat if vec != 0] + quotient = ModulesWithBasis.ParentMethods.__dict__["quotient"] + class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index 0da4ce1a6ca..78325811bce 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -1,10 +1,5 @@ r""" Quotients of Modules With Basis - -sage: H = IwahoriHeckeAlgebraT("A2", QQ(0)) -sage: C = H.submodule(H.center_basis(), H, category=FiniteDimensionalAlgebrasWithBasis(QQ).Subquotients()) -sage: TestSuite(C).run() - """ #***************************************************************************** # Copyright (C) 2010 Florent Hivert @@ -20,6 +15,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): r""" + A class for quotients of a module with basis by a submodule. """ @staticmethod def __classcall_private__(cls, submodule, category = None): @@ -28,6 +24,11 @@ def __classcall_private__(cls, submodule, category = None): TESTS:: + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) + sage: J1 = QuotientModuleWithBasis(I) + sage: J2 = QuotientModuleWithBasis(I, category=Modules(QQ).WithBasis().Quotients()) + sage: J1 is J2 """ category = ModulesWithBasis(submodule.base_ring()).Quotients().or_subcategory(category, join=True) return super(QuotientModuleWithBasis, cls).__classcall__( @@ -64,7 +65,7 @@ def __init__(self, submodule, category): def ambient(self): r""" - Returns the ambient space of ``self`` + Return the ambient space of ``self``. EXAMPLES:: From 0daa497c9d3c29a3a14e3742bb9c71ecca3a49bf Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 10 Jul 2014 15:34:57 -0700 Subject: [PATCH 018/665] remove center for group algebras, center_basis instead --- src/sage/categories/groups.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 2811e6e1e33..ae895428ea7 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -522,9 +522,9 @@ def _conjugacy_classes_representatives_underlying_group(self): """ return self.group().conjugacy_classes_representatives() - def center(self): + def center_basis(self): r""" - Return the center of the group algebra. + Return a basis of the center of the group algebra. The canonical basis of the center of the group algebra is the family `(f_\sigma)_{\sigma\in C}`, where `C` is @@ -534,31 +534,25 @@ def center(self): OUTPUT: - - A free module `V` indexed by conjugacy class - representatives of the group; its elements represent - formal linear combinations of the canonical basis - elements. + - ``list`` of elements of ``self`` .. WARNING:: - This method requires the underlying group to have a method ``conjugacy_classes_representatives`` (every permutation group has one, thanks GAP!). - - The product has not been implemented yet. EXAMPLES:: - sage: SymmetricGroupAlgebra(ZZ,3).center() - Free module generated by {[2, 3, 1], [2, 1, 3], [1, 2, 3]} over Integer Ring + sage: sage: SymmetricGroupAlgebra(ZZ,3).center_basis() + [[2, 3, 1], [2, 1, 3], [1, 2, 3]] .. SEEALSO:: - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - I = self._conjugacy_classes_representatives_underlying_group() - from sage.combinat.free_module import CombinatorialFreeModule - return CombinatorialFreeModule(self.base_ring(), I) + return self._conjugacy_classes_representatives_underlying_group() # Coalgebra structure From c7731402471f759342818c6089c6e1c6be670ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 11 Jul 2014 15:08:58 +0200 Subject: [PATCH 019/665] 11111: trivial ReST fix --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fb838af8908..9526742362c 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -111,7 +111,7 @@ def radical_basis(self, cache_products=True): sage: A.radical_basis(cache_products=False) [] - .. TODO:: explain and check this example:: + .. TODO:: explain and check this example :: From 449c2625fe465a8314b5c6c78294a7c815bb9668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 11 Jul 2014 15:25:08 +0200 Subject: [PATCH 020/665] 11111: imported maschkethm-av.patch from the Sage-Combinat queue --- src/sage/categories/finite_groups.py | 27 ++++++++++++++++++++ src/sage/categories/semisimple_algebras.py | 2 +- src/sage/categories/sets_cat.py | 29 +++++++++++++++++++--- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 0d7fe354548..a31764f6664 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -9,6 +9,7 @@ #****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.algebra_functor import AlgebrasCategory class FiniteGroups(CategoryWithAxiom): r""" @@ -200,3 +201,29 @@ def conjugacy_class(self): """ return self.parent().conjugacy_class(self) + class Algebras(AlgebrasCategory): + + def extra_super_categories(self): + r""" + Implement Maschke's theorem. + + In characteristic 0 all finite group algebras are semisimple. + + EXAMPLES:: + + sage: FiniteGroups().Algebras(QQ).is_subcategory(SemisimpleAlgebras(QQ)) + True + sage: FiniteGroups().Algebras(FiniteField(7)).is_subcategory(SemisimpleAlgebras(QQ)) + False + sage: FiniteGroups().Algebras(ZZ).is_subcategory(SemisimpleAlgebras(ZZ)) + False + sage: FiniteGroups().Algebras(Fields()).is_subcategory(SemisimpleAlgebras(Fields())) + False + """ + from sage.categories.semisimple_algebras import SemisimpleAlgebras + from sage.categories.fields import Fields + K = self.base_ring() + if (K in Fields) and K.characteristic() == 0: + return [SemisimpleAlgebras(self.base_ring())] + else: + return [] diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 7c142037aa5..f657c2f587e 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -11,7 +11,7 @@ from category_types import Category_over_base_ring from algebras import Algebras from sage.misc.cachefunc import cached_method - +import operator class SemisimpleAlgebras(Category_over_base_ring): """ diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index cce28666b27..1a1dbb62776 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1395,6 +1395,18 @@ def algebra(self, base_ring, category = None): sage: A in HopfAlgebras(QQ) True + By Maschke's theorem, for a finite group whose cardinality + does not divide the characteristic of the base field, the + algebra is semisimple:: + + sage: SymmetricGroup(5).algebra(QQ) in SemisimpleAlgebras(QQ) + True + sage: CyclicPermutationGroup(10).algebra(FiniteField(5)) in SemisimpleAlgebras + False + sage: CyclicPermutationGroup(10).algebra(FiniteField(7)) in SemisimpleAlgebras + True + + One may specify for which category one takes the algebra:: sage: A = S.algebra(QQ, category = Sets()); A @@ -1435,12 +1447,12 @@ def algebra(self, base_ring, category = None): sage: A = Z3.algebra(QQ, category = Monoids()); A Free module generated by Ring of integers modulo 3 over Rational Field sage: A.category() - Category of monoid algebras over Rational Field + Category of finite dimensional monoid algebras over Rational Field sage: A = Z3.algebra(QQ, category = CommutativeAdditiveGroups()); A Free module generated by Ring of integers modulo 3 over Rational Field sage: A.category() - Category of commutative additive group algebras over Rational Field + Category of finite dimensional commutative additive group algebras over Rational Field Similarly, on , we obtain for additive magmas, monoids, groups. @@ -1471,7 +1483,18 @@ def algebra(self, base_ring, category = None): Constructing its algebra is ambiguous. Please use, e.g., S.algebra(QQ, category = Semigroups())""".format(self)) from sage.combinat.free_module import CombinatorialFreeModule - return CombinatorialFreeModule(base_ring, self, category = category.Algebras(base_ring)) + from sage.categories.groups import Groups + from sage.categories.fields import Fields + category = category.Algebras(base_ring) + # Maschke's theorem: under some conditions, the algebra is semisimple + # If base_ring is of characteristic 0, this is handled in the FiniteGroups.Algebras category + if (self in Groups().Finite()) and (base_ring in Fields) + and base_ring.characteristic() > 0 + and hasattr(self, "cardinality") + and self.cardinality() % base_ring.characteristic() != 0: + from sage.categories.semisimple_algebras import SemisimpleAlgebras + category = (category, SemisimpleAlgebras(base_ring)) + return CombinatorialFreeModule(base_ring, self, category = category) class ElementMethods: From 5c7977a72ef687f17f29a53ada0a8324d70a1204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 11 Jul 2014 17:01:16 +0200 Subject: [PATCH 021/665] 11111: trivial Python syntax fix --- src/sage/categories/sets_cat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 987c3346866..8f1fcccb68f 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1488,9 +1488,9 @@ def algebra(self, base_ring, category = None): category = category.Algebras(base_ring) # Maschke's theorem: under some conditions, the algebra is semisimple # If base_ring is of characteristic 0, this is handled in the FiniteGroups.Algebras category - if (self in Groups().Finite()) and (base_ring in Fields) - and base_ring.characteristic() > 0 - and hasattr(self, "cardinality") + if self in Groups().Finite() and base_ring in Fields \ + and base_ring.characteristic() > 0 \ + and hasattr(self, "cardinality") \ and self.cardinality() % base_ring.characteristic() != 0: from sage.categories.semisimple_algebras import SemisimpleAlgebras category = (category, SemisimpleAlgebras(base_ring)) From 370ff43d925825e551bb1b6f804b1b9aeb79b688 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 11 Jul 2014 09:21:36 -0700 Subject: [PATCH 022/665] fix tests --- src/sage/categories/groups.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index ae895428ea7..e8c5c404686 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -544,7 +544,7 @@ def center_basis(self): EXAMPLES:: - sage: sage: SymmetricGroupAlgebra(ZZ,3).center_basis() + sage: SymmetricGroupAlgebra(ZZ,3).center_basis() [[2, 3, 1], [2, 1, 3], [1, 2, 3]] .. SEEALSO:: @@ -678,14 +678,14 @@ def central_form(self): EXAMPLES:: sage: QS3 = SymmetricGroupAlgebra(QQ, 3) - sage: A=QS3([2,3,1])+QS3([3,1,2]) + sage: A = QS3([2,3,1])+QS3([3,1,2]) sage: A.central_form() B[[2, 3, 1]] sage: QS4 = SymmetricGroupAlgebra(QQ, 4) - sage: B=sum(len(s.cycle_type())*QS4(s) for s in Permutations(4)) + sage: B = sum(len(s.cycle_type())*QS4(s) for s in Permutations(4)) sage: B.central_form() 4*B[[1, 2, 3, 4]] + 3*B[[2, 1, 3, 4]] + 2*B[[2, 1, 4, 3]] + 2*B[[2, 3, 1, 4]] + B[[2, 3, 4, 1]] - sage: QG=GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])) + sage: QG = GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])) sage: sum(i for i in QG.basis()).central_form() B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)] From 7129e591f8270a68939751054168fb720ba73d3b Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 14 Jul 2014 14:15:44 -0700 Subject: [PATCH 023/665] fix doctest --- src/sage/modules/subquotient_module_with_basis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index 78325811bce..1b7151a95b5 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -24,11 +24,13 @@ def __classcall_private__(cls, submodule, category = None): TESTS:: + sage: from sage.modules.subquotient_module_with_basis import QuotientModuleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) sage: J1 = QuotientModuleWithBasis(I) sage: J2 = QuotientModuleWithBasis(I, category=Modules(QQ).WithBasis().Quotients()) sage: J1 is J2 + True """ category = ModulesWithBasis(submodule.base_ring()).Quotients().or_subcategory(category, join=True) return super(QuotientModuleWithBasis, cls).__classcall__( @@ -45,7 +47,7 @@ def __init__(self, submodule, category): sage: Y Free module generated by {2} over Rational Field sage: Y.category() - Join of Category of vector spaces with basis over Rational Field and Category of quotients of sets + Join of Category of finite dimensional modules with basis over Rational Field and Category of vector spaces with basis over Rational Field and Category of quotients of sets sage: Y.basis().list() [B[2]] sage: TestSuite(Y).run() From f3be7829de8bf570b40120fc7fe778536275f9d5 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 15 Jul 2014 12:56:49 -0700 Subject: [PATCH 024/665] center_basis for group algebras now return a list of elements of --- src/sage/categories/groups.py | 3 ++- src/sage/categories/modules_with_basis.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index e8c5c404686..b90981aad70 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -552,7 +552,8 @@ def center_basis(self): - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - return self._conjugacy_classes_representatives_underlying_group() + return [self(c) for c in + self._conjugacy_classes_representatives_underlying_group()] # Coalgebra structure diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index c8be15bba99..3b1f2e0f272 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1730,6 +1730,7 @@ class TriangularModuleMorphism(ModuleMorphismByLinearity): sage: [phi.preimage(x[i]) for i in range(1, 4)] [-1/3*B[1] + B[2] - 1/12*B[3], 1/4*B[3], 1/3*B[1] - 1/6*B[3]] """ + def __init__(self, on_basis, domain, triangular = "upper", unitriangular=False, codomain = None, category = None, cmp = None, inverse = None, inverse_on_support = None, invertible = None): From f16cfbf4b129f3ad63fc27753c6336f79cd5527b Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 15 Jul 2014 15:19:57 -0700 Subject: [PATCH 025/665] center_basis for group algebra is now really a basis --- src/sage/categories/finite_dimensional_modules_with_basis.py | 2 +- src/sage/categories/groups.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index a1b8c68fe13..1ec7dff38e8 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -270,7 +270,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis() + on_basis = self.on_basis basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index b90981aad70..fd1b96f044e 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -552,8 +552,8 @@ def center_basis(self): - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - return [self(c) for c in - self._conjugacy_classes_representatives_underlying_group()] + return [sum([self(c) for c in conj]) for conj in + self.basis().keys().conjugacy_classes()] # Coalgebra structure From 11d826d2cfc8f686cac3df772569c03ca05d23c1 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 15 Jul 2014 17:43:56 -0700 Subject: [PATCH 026/665] central_form + doctest --- src/sage/categories/groups.py | 25 ++++++++++++----------- src/sage/categories/modules_with_basis.py | 6 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index fd1b96f044e..bb66a617b6b 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -544,8 +544,8 @@ def center_basis(self): EXAMPLES:: - sage: SymmetricGroupAlgebra(ZZ,3).center_basis() - [[2, 3, 1], [2, 1, 3], [1, 2, 3]] + sage: SymmetricGroup(3).algebra(QQ).center_basis() + [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] .. SEEALSO:: @@ -664,8 +664,8 @@ def central_form(self): .. WARNING:: - This method requires the underlying group to - have a method ``conjugacy_classes_representatives`` - (every permutation group has one, thanks GAP!). + have a method + ``conjugacy_classes_representatives_underlying_group``. - This method does not check that the element is indeed central. Use the method :meth:`Monoids.Algebras.ElementMethods.is_central` @@ -678,14 +678,15 @@ def central_form(self): EXAMPLES:: - sage: QS3 = SymmetricGroupAlgebra(QQ, 3) - sage: A = QS3([2,3,1])+QS3([3,1,2]) + sage: QS3 = SymmetricGroup(3).algebra(QQ) + sage: A = QS3([2,3,1]) + QS3([3,1,2]) sage: A.central_form() - B[[2, 3, 1]] - sage: QS4 = SymmetricGroupAlgebra(QQ, 4) + B[(1,2,3)] + sage: QS4 = SymmetricGroup(4).algebra(QQ) sage: B = sum(len(s.cycle_type())*QS4(s) for s in Permutations(4)) sage: B.central_form() - 4*B[[1, 2, 3, 4]] + 3*B[[2, 1, 3, 4]] + 2*B[[2, 1, 4, 3]] + 2*B[[2, 3, 1, 4]] + B[[2, 3, 4, 1]] + 4*B[()] + 3*B[(1,2)] + 2*B[(1,2)(3,4)] + 2*B[(1,2,3)] + B[(1,2,3,4)] + sage: QG = GroupAlgebras(QQ).example(PermutationGroup([[(1,2,3),(4,5)],[(3,4)]])) sage: sum(i for i in QG.basis()).central_form() B[()] + B[(4,5)] + B[(3,4,5)] + B[(2,3)(4,5)] + B[(2,3,4,5)] + B[(1,2)(3,4,5)] + B[(1,2,3,4,5)] @@ -695,7 +696,7 @@ def central_form(self): - :meth:`Groups.Algebras.ParentMethods.center` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - Z = self.parent().center() + from sage.combinat.free_module import CombinatorialFreeModule + Z = CombinatorialFreeModule(self.base_ring(), + self.parent()._conjugacy_classes_representatives_underlying_group()) return sum(self[i] * Z.basis()[i] for i in Z.basis().keys()) - - diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 3b1f2e0f272..5eb21dd2d1e 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -509,10 +509,10 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: basis [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] sage: center = S3A.submodule(basis, - ... category = AlgebrasWithBasis(QQ).Subobjects(), - ... already_echelonized = True) + ... category = AlgebrasWithBasis(QQ).Subobjects(), + ... already_echelonized = True) sage: center - A subobject of Group algebra of Symmetric group of order 3! as a permutation group over Rational Field + Free module generated by {0, 1, 2} over Rational Field sage: center in Algebras True sage: center.print_options(prefix='c') From 64a87bfaa09322710f081db896b757765c8c33cd Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 15 Jul 2014 17:54:29 -0700 Subject: [PATCH 027/665] undo previous bad modification --- src/sage/categories/finite_dimensional_modules_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 1ec7dff38e8..a1b8c68fe13 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -270,7 +270,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis + on_basis = self.on_basis() basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) From 872e2bc0225b6929ed8cc052a63850c892abe723 Mon Sep 17 00:00:00 2001 From: Jan Keitel Date: Sun, 20 Jul 2014 21:50:17 +0200 Subject: [PATCH 028/665] Remove old reference from spherical harmonics. --- src/sage/functions/special.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 05d8c011610..41162a5c312 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -625,8 +625,6 @@ class SphericalHarmonic(BuiltinFunction): For integers `n > -1`, `|m| \leq n`, simplification is done automatically. Numeric evaluation is supported for complex `n` and `m`. - Reference: Merzbacher 9.64 - EXAMPLES:: sage: x, y = var('x, y') From 3b2be6ee2adedf5ce23618f17ffe348e1202cdb9 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 13:54:28 -0700 Subject: [PATCH 029/665] semi simple commutative decomposition bugged code --- src/sage/categories/groups.py | 1 + src/sage/categories/semisimple_algebras.py | 73 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index bb66a617b6b..0c874a6db16 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -522,6 +522,7 @@ def _conjugacy_classes_representatives_underlying_group(self): """ return self.group().conjugacy_classes_representatives() + @cached_method def center_basis(self): r""" Return a basis of the center of the group algebra. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index f657c2f587e..42049f73214 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -9,10 +9,13 @@ #****************************************************************************** from category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from algebras import Algebras from sage.misc.cachefunc import cached_method import operator +from sage.rings.integer_ring import ZZ + class SemisimpleAlgebras(Category_over_base_ring): """ The category of semisimple algebras over a given base ring. @@ -53,3 +56,73 @@ def super_categories(self): """ R = self.base_ring() return [Algebras(R)] + + class Commutative(CategoryWithAxiom_over_base_ring): + + from sage.rings.integer_ring import ZZ + from sage.categories.associative_algebras import AssociativeAlgebras + + class ParentMethods: + + def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): + r""" + Decompose a commutative semi-simple algebra ``A`` into a direct sum of simple A-modules. + + Return a list of generators of simple A-modules. + + EXAMPLES: + + sage: A5 = SymmetricGroupAlgebra(QQ,5) + sage: Z5 = A5.center() + sage: semi_simple_commutative_decomposition(Z5) + [B[0] - 1/3*B[3] + 1/6*B[6], + B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], + B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6], + B[0] + 1/2*B[1] + 1/4*B[2] - 1/4*B[5] - 1/4*B[6], + B[0] - 1/2*B[1] + 1/4*B[2] + 1/4*B[5] - 1/4*B[6], + B[0] + 1/5*B[1] - 1/5*B[2] + 1/5*B[3] - 1/5*B[4] + 1/5*B[5], + B[0] - 1/5*B[1] - 1/5*B[2] + 1/5*B[3] + 1/5*B[4] - 1/5*B[5]] + """ + #Terminal case and stuffs + if listGen==None: + listGen = self.basis().list() + if self.dimension() == 1: + if topLevel: + return self.basis().list() + else: + return [x.lift() for x in self.basis()] + + #Searching for a good generator... + res = [] + B = self.basis() + while len(res)<2: + if listGen==[]: + raise Exception("Unable to fully decompose...") + curGen = listGen[ZZ.random_element(len(listGen))] + listGen.remove(curGen) + phi = self.module_morphism(on_basis=lambda i: + curGen*B[i], + codomain=self, + triangular=True) + # phi = self.module_morphism(on_basis=lambda i: + # curGen*self.monomial(i), + # codomain=self, + # triangular=True) + return phi + aMat = phi.matrix(self.base_ring()) + res = aMat.eigenspaces_right() + + #Gotcha! Let's settle the algebra... + + res = [vector_space for _,vector_space in res] + res = [[self.from_vector(vector) for vector in eigenspace.basis()] + for eigenspace in res] + + decomp = [self.submodule(v, category=AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects()) for v in res] + + #Recursive on decomp + res = [x for space in decomp for x in space.semi_simple_commutative_decomposition(topLevel=False)] + if topLevel: + return res + else: + return map( lambda x: x.lift(), res) From b99c59cbf493c2eb068208d989945ebd27ff03e3 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 17:37:11 -0700 Subject: [PATCH 030/665] product of SubModuleWithBasis --- .../modules/subquotient_module_with_basis.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index 1b7151a95b5..5926e369f63 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -208,3 +208,22 @@ def retract(self): True """ return self.lift.section() + def _mul_(self, left): + r""" + Product of two elements. + INPUT:: + + - ``self``, ``left`` -- two elements + + If B is a SubModuleWithBasis of A, then the multiplication law of B is + inherited from the multiplication of A. + + EXAMPLES:: + + sage: Z = SymmetricGroup(5).algebra(QQ).center() + sage: B = Z.basis() + sage: B[3] * B[2] + 4*B[2] + 6*B[3] + 5*B[6] + """ + p = self.parent() + return p.retract(p.lift(self) * p.lift(left)) From 3b1a7628cb200bc2d4a27d5b8073d55a587c9c4a Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 18:25:00 -0700 Subject: [PATCH 031/665] SemisimpleAlgebras, orthogonal idempotents for commutative semisimple algebras --- .../finite_dimensional_modules_with_basis.py | 2 +- src/sage/categories/groups.py | 1 + src/sage/categories/semisimple_algebras.py | 88 +++++++++++++------ 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index a1b8c68fe13..1ec7dff38e8 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -270,7 +270,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis() + on_basis = self.on_basis basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 0c874a6db16..a6a3e309287 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -12,6 +12,7 @@ #****************************************************************************** from sage.misc.lazy_import import LazyImport +from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.monoids import Monoids from sage.categories.algebra_functor import AlgebrasCategory diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 42049f73214..7ce5f6c2b46 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -10,12 +10,12 @@ from category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from algebras import Algebras from sage.misc.cachefunc import cached_method -import operator - +from algebras import Algebras +from sage.categories.associative_algebras import AssociativeAlgebras from sage.rings.integer_ring import ZZ + class SemisimpleAlgebras(Category_over_base_ring): """ The category of semisimple algebras over a given base ring. @@ -59,29 +59,42 @@ def super_categories(self): class Commutative(CategoryWithAxiom_over_base_ring): - from sage.rings.integer_ring import ZZ - from sage.categories.associative_algebras import AssociativeAlgebras - class ParentMethods: - def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): + @cached_method + def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): r""" - Decompose a commutative semi-simple algebra ``A`` into a direct sum of simple A-modules. + Decompose a commutative finite dimensional semi-simple algebra + ``A`` into a direct sum of simple A-modules. + + INPUT:: + + - ``self`` a finite dimensional semisimple commutative algebra. + + OUTPUT:: + + - list of elements of ``self`` each generating a simple + submodule of ``self`` in direct sum with the others. The list + is maximal. Return a list of generators of simple A-modules. EXAMPLES: - sage: A5 = SymmetricGroupAlgebra(QQ,5) - sage: Z5 = A5.center() - sage: semi_simple_commutative_decomposition(Z5) - [B[0] - 1/3*B[3] + 1/6*B[6], - B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], - B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6], - B[0] + 1/2*B[1] + 1/4*B[2] - 1/4*B[5] - 1/4*B[6], - B[0] - 1/2*B[1] + 1/4*B[2] + 1/4*B[5] - 1/4*B[6], - B[0] + 1/5*B[1] - 1/5*B[2] + 1/5*B[3] - 1/5*B[4] + 1/5*B[5], - B[0] - 1/5*B[1] - 1/5*B[2] + 1/5*B[3] + 1/5*B[4] - 1/5*B[5]] + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: Z5._semi_simple_commutative_decomposition_generators() + [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + B[3] + + B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - + 1/5*B[5], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - + 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] """ #Terminal case and stuffs if listGen==None: @@ -104,11 +117,6 @@ def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): curGen*B[i], codomain=self, triangular=True) - # phi = self.module_morphism(on_basis=lambda i: - # curGen*self.monomial(i), - # codomain=self, - # triangular=True) - return phi aMat = phi.matrix(self.base_ring()) res = aMat.eigenspaces_right() @@ -118,11 +126,41 @@ def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): res = [[self.from_vector(vector) for vector in eigenspace.basis()] for eigenspace in res] - decomp = [self.submodule(v, category=AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects()) for v in res] + decomp = [self.submodule(v, + category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] #Recursive on decomp - res = [x for space in decomp for x in space.semi_simple_commutative_decomposition(topLevel=False)] + res = [x for space in decomp for x in + space._semi_simple_commutative_decomposition_generators(topLevel=False)] if topLevel: return res else: return map( lambda x: x.lift(), res) + + @cached_method + r""" + Return the minimal orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z5.orthogonal_idempotents() + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], + 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + + 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - + 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + """ + def orthogonal_idempotents(self): + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in + self._semi_simple_commutative_decomposition_generators()] From f94621ef0895e8302f6921301379787cc8db3a3e Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 18:30:49 -0700 Subject: [PATCH 032/665] indentation --- src/sage/categories/semisimple_algebras.py | 45 +++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 7ce5f6c2b46..279c9c1fcb9 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -138,29 +138,30 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev return map( lambda x: x.lift(), res) @cached_method - r""" - Return the minimal orthogonal idempotents of ``self``. - - EXAMPLES:: - - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + - 45*B[6] - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z5.orthogonal_idempotents() - sage: orth - [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + - 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], - 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + - 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - - 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] - """ def orthogonal_idempotents(self): + r""" + Return the minimal orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z5.orthogonal_idempotents() + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], + 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + + 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - + 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] From f0bb894eacf36bbfee30a058b01b202ad7640bfd Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 19:29:43 -0700 Subject: [PATCH 033/665] _mul_ at the right place --- src/sage/categories/algebras.py | 24 +++++++++++++++++++ .../modules/subquotient_module_with_basis.py | 22 ++--------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index eabf44888e5..14e9fa2fd14 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -23,6 +23,7 @@ from sage.categories.quotients import QuotientsCategory from sage.categories.dual import DualObjectsCategory from sage.categories.tensor import TensorProductsCategory +from sage.categories.subobjects import SubobjectsCategory from sage.categories.associative_algebras import AssociativeAlgebras class Algebras(CategoryWithAxiom_over_base_ring): @@ -217,3 +218,26 @@ def extra_super_categories(self): """ from sage.categories.coalgebras import Coalgebras return [Coalgebras(self.base_category().base_ring())] + class Subobjects(SubobjectsCategory): + + class ElementMethods: + + def _mul_(self, right): + r""" + Product of two elements. + INPUT:: + + - ``self``, ``right`` -- two elements + + If B is a SubModuleWithBasis of A, then the multiplication law of B is + inherited from the multiplication of A. + + EXAMPLES:: + + sage: Z = SymmetricGroup(5).algebra(QQ).center() + sage: B = Z.basis() + sage: B[3] * B[2] + 4*B[2] + 6*B[3] + 5*B[6] + """ + p = self.parent() + return p.retract( self.lift() * right.lift()) diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index 5926e369f63..edf8954f85c 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -150,7 +150,8 @@ def __init__(self, basis, ambient, category): """ import operator ring = ambient.base_ring() - CombinatorialFreeModule.__init__(self, ring, basis.keys(), category = category) + CombinatorialFreeModule.__init__(self, ring, basis.keys(), category = + category.Subobjects()) self._ambient = ambient self._basis = basis self.lift_on_basis = self._basis.__getitem__ @@ -208,22 +209,3 @@ def retract(self): True """ return self.lift.section() - def _mul_(self, left): - r""" - Product of two elements. - INPUT:: - - - ``self``, ``left`` -- two elements - - If B is a SubModuleWithBasis of A, then the multiplication law of B is - inherited from the multiplication of A. - - EXAMPLES:: - - sage: Z = SymmetricGroup(5).algebra(QQ).center() - sage: B = Z.basis() - sage: B[3] * B[2] - 4*B[2] + 6*B[3] + 5*B[6] - """ - p = self.parent() - return p.retract(p.lift(self) * p.lift(left)) From a203460edf21c556da86af27a940cea8699f1cc6 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 19:35:30 -0700 Subject: [PATCH 034/665] tests --- src/sage/categories/semisimple_algebras.py | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 279c9c1fcb9..69fdb0d24c7 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -88,13 +88,14 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) - sage: Z5._semi_simple_commutative_decomposition_generators() - [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + B[3] + - B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] - + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - - 1/5*B[5], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] - + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - - 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] + sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: sorted(gens, key=str) + [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] + + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], B[0] - 1/2*B[1] + + 1/4*B[3] + 1/4*B[4] - 1/4*B[6], B[0] - 1/3*B[2] + + 1/6*B[6], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6]] """ #Terminal case and stuffs if listGen==None: @@ -152,15 +153,17 @@ def orthogonal_idempotents(self): 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() - sage: orth - [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + - 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], - 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + - 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - - 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + sage: orth = Z5.orthogonal_idempotents() + sage: sorted(orth, key=str) + [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - + 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] + - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + 1/30*B[3] + + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - 1/10*B[2] + 1/20*B[6], + 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - + 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - + 1/24*B[4] + 1/24*B[5]] """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in From 75e4f5aceb122fa4158f60831233ac095f100a8b Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 21:56:14 -0700 Subject: [PATCH 035/665] _lift_idempotent for elements of sub-algebras --- src/sage/categories/algebras.py | 26 +++++++++++++++++++ .../finite_dimensional_algebras_with_basis.py | 4 +++ src/sage/categories/semisimple_algebras.py | 18 ++++++++----- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 14e9fa2fd14..97ebc9e2b55 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -241,3 +241,29 @@ def _mul_(self, right): """ p = self.parent() return p.retract( self.lift() * right.lift()) + + def _lift_idempotent(self): + r""" + Lift an idempotent of parent of ``self`` into an indempotent of + parent of ``self.lift()`` + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: Z3 = A3.center() + sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z3.orthogonal_idempotents() + sage: x = orth[2]._lift_idempotent() + sage: x not in Z3 and x in A3 + True + + TODO: better documentation. + """ + idempOld = None + idemp = self.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 9526742362c..681775b4686 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -343,6 +343,10 @@ def center(self): center.rename("Center of {}".format(self)) return center + # def orthogonal_idempotents(self): + # pass + + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 69fdb0d24c7..d440b82d124 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -84,9 +84,6 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] - + 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: gens = Z5._semi_simple_commutative_decomposition_generators() sage: sorted(gens, key=str) @@ -143,14 +140,19 @@ def orthogonal_idempotents(self): r""" Return the minimal orthogonal idempotents of ``self``. + INPUT:: + + - ``self`` a commutative semisimple algebra + + OUTPUT:: + + - list of idempotents of ``self`` + EXAMPLES:: sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + - 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() sage: orth = Z5.orthogonal_idempotents() @@ -164,6 +166,10 @@ def orthogonal_idempotents(self): 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5]] + sage: orth[2] * orth[4] + 0 + sage: orth[1] ** 2 == orth[1] + True """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in From 7caba0d400b94c3b19d311249e8c9f146a5bd591 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 10:32:47 -0700 Subject: [PATCH 036/665] orthogonal idempotents for semisimple algebras --- .../finite_dimensional_algebras_with_basis.py | 10 +++--- src/sage/categories/groups.py | 1 - src/sage/categories/semisimple_algebras.py | 32 ++++++++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 681775b4686..04bc12fb536 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -336,18 +336,18 @@ def center(self): sage: TestSuite(center).run() """ - category = Algebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() + if self in SemisimpleAlgebras(self.base_ring()): + category = SemisimpleAlgebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() + else: + category = Algebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() center = self.submodule(self.center_basis(), category = category, already_echelonized = True) center.rename("Center of {}".format(self)) return center - # def orthogonal_idempotents(self): - # pass - - class ElementMethods: + def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ Return the matrix of the action of ``self`` on the algebra. diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index a6a3e309287..c28059f7f35 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -523,7 +523,6 @@ def _conjugacy_classes_representatives_underlying_group(self): """ return self.group().conjugacy_classes_representatives() - @cached_method def center_basis(self): r""" Return a basis of the center of the group algebra. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index d440b82d124..90e8147c46d 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -57,6 +57,32 @@ def super_categories(self): R = self.base_ring() return [Algebras(R)] + class ParentMethods: + + @cached_method + def orthogonal_idempotents(self): + r""" + Return a maximal list of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- semisimple algebra + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: orth3 = A3.orthogonal_idempotents() + sage: sorted(orth3, key=str) + [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], + 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + """ + Z = self.center() + orth = Z.orthogonal_idempotents() + return [x._lift_idempotent() for x in orth] + + class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -67,11 +93,11 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev Decompose a commutative finite dimensional semi-simple algebra ``A`` into a direct sum of simple A-modules. - INPUT:: + INPUT: - ``self`` a finite dimensional semisimple commutative algebra. - OUTPUT:: + OUTPUT: - list of elements of ``self`` each generating a simple submodule of ``self`` in direct sum with the others. The list @@ -84,7 +110,6 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: gens = Z5._semi_simple_commutative_decomposition_generators() sage: sorted(gens, key=str) [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + @@ -153,7 +178,6 @@ def orthogonal_idempotents(self): sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() sage: orth = Z5.orthogonal_idempotents() sage: sorted(orth, key=str) From 8aa7db9b6f868b15eabb55b257ab65f2813fa65c Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 10:38:39 -0700 Subject: [PATCH 037/665] tests --- src/sage/categories/semisimple_algebras.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 90e8147c46d..5bfafd73b44 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -77,10 +77,21 @@ def orthogonal_idempotents(self): 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + + :: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: sorted(orth, key=str) + [B['x'], B['y']] """ Z = self.center() orth = Z.orthogonal_idempotents() - return [x._lift_idempotent() for x in orth] + return [x.lift() for x in orth] class Commutative(CategoryWithAxiom_over_base_ring): From b2bb56644c544afeaa9e833cf9f59ae426aa8898 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 11:33:32 -0700 Subject: [PATCH 038/665] beginning of implemantation for general algebras --- src/sage/categories/algebras.py | 54 ++++++++++--------- .../finite_dimensional_algebras_with_basis.py | 12 +++++ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 97ebc9e2b55..4044a04f94e 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -119,6 +119,34 @@ def _div_(self, y): class Quotients(QuotientsCategory): + class ElementMethods: + + def _lift_idempotent(self): + r""" + Lift an idempotent of parent of ``self`` into an indempotent of + parent of ``self.lift()`` + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: Z3 = A3.center() + sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z3.orthogonal_idempotents() + sage: x = orth[2]._lift_idempotent() + sage: x not in Z3 and x in A3 + True + + TODO: better documentation. + """ + idempOld = None + idemp = self.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp + class ParentMethods: def algebra_generators(self): @@ -241,29 +269,3 @@ def _mul_(self, right): """ p = self.parent() return p.retract( self.lift() * right.lift()) - - def _lift_idempotent(self): - r""" - Lift an idempotent of parent of ``self`` into an indempotent of - parent of ``self.lift()`` - - EXAMPLES:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: Z3 = A3.center() - sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z3.orthogonal_idempotents() - sage: x = orth[2]._lift_idempotent() - sage: x not in Z3 and x in A3 - True - - TODO: better documentation. - """ - idempOld = None - idemp = self.lift() - p = idemp.parent() - while idemp <> idempOld: - tmp = idemp - idemp = (p.one() - (p.one() - idemp**2)**2) - idempOld = tmp - return idemp diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 04bc12fb536..bd068e464cd 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -346,6 +346,18 @@ def center(self): center.rename("Center of {}".format(self)) return center + def orthogonal_idempotent(self): + r""" + Return a maximal family of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- a finite dimensional algebra + """ + Aquo = self.semisimple_quotient() + orth_quo = Aquo.orthogonal_idempotents() + return [x._lift_idempotent() for x in orth_quo] + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): From a156a1e71555e573ea9e8787e7d34e5c992bfe6f Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 30 Jul 2014 11:39:42 -0700 Subject: [PATCH 039/665] radical for SemisimpleAlgebras --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index bd068e464cd..d480845784c 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -147,6 +147,9 @@ def radical_basis(self, cache_products=True): from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + if self in SemisimpleAlgebras(self.base_ring()): + return self.from_vector(vector(self.zero())) + if cache_products is True: product_on_basis = cached_function(self.product_on_basis) else: From ebb8cb569d02a1aea1fa4eac573d8bb1e831c857 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 11 Aug 2014 18:13:53 -0700 Subject: [PATCH 040/665] example --- .../finite_dimensional_algebras_with_basis.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index d480845784c..c3aee19cbeb 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -356,6 +356,16 @@ def orthogonal_idempotent(self): INPUT: - ``self`` -- a finite dimensional algebra + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: A.orthogonal_idempotent() + [y, x] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() From d7f04d5ee63e8d5f6a2bc8f9d21d76f1d725f813 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 18 Aug 2014 10:22:44 +0100 Subject: [PATCH 041/665] Trac 9787: coerce points into base ring for Lagrange interpolation --- src/sage/rings/polynomial/polynomial_ring.py | 170 ++++++++++--------- 1 file changed, 87 insertions(+), 83 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index d9e3958edf8..828a7df8a12 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1569,49 +1569,41 @@ def _ideal_class_(self, n=0): return Ideal_1poly_field def divided_difference(self, points, full_table=False): - """ - Return the Newton divided-difference coefficients of the `n`-th - Lagrange interpolation polynomial of ``points``. - - If ``points`` are `n+1` distinct points - `(x_0, f(x_0)), (x_1, f(x_1)), \dots, (x_n, f(x_n))`, then `P_n(x)` - is the `n`-th Lagrange interpolation polynomial of `f(x)` that - passes through the points `(x_i, f(x_i))`. This method returns - the coefficients `F_{i,i}` such that - - .. MATH:: - - P_n(x) = \sum_{i=0}^n F_{i,i} \prod_{j=0}^{i-1} (x - x_j) - + r""" + Return the Newton divided-difference coefficients of the + Lagrange interpolation polynomial through ``points``. INPUT: - - ``points`` -- a list of tuples - `(x_0, f(x_0)), (x_1, f(x_1)), \dots, (x_n, f(x_n))` where each - `x_i \\neq x_j` for `i \\neq j` - - - ``full_table`` -- (default: ``False``) if ``True`` then return the - full divided-difference table; if ``False`` then only return - entries along the main diagonal. The entries along the main - diagonal are the Newton divided-difference coefficients `F_{i,i}`. + - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), + \dots, (x_n, y_n)` of elements of the base ring of ``self``, + where `x_i \neq x_j` for `i \neq j`. + - ``full_table`` -- boolean (default: ``False``): If ``True``, + return the full divided-difference table. If ``False``, + only return entries along the main diagonal; these are the + Newton divided-difference coefficients `F_{i,i}`. OUTPUT: - - The Newton divided-difference coefficients of the `n`-th Lagrange - interpolation polynomial that passes through the points in - ``points``. + The Newton divided-difference coefficients of the `n`-th + Lagrange interpolation polynomial `P_n(x)` that passes through + the points in ``points`` (see :meth:`lagrange_polynomial`). + These are the coefficients `F_{0,0}, F_{1,1}, \dots, `F_{n,n}` + such that + .. math:: + + P_n(x) = \sum_{i=0}^n F_{i,i} \prod_{j=0}^{i-1} (x - x_j) EXAMPLES: - Only return the divided-difference coefficients `F_{i,i}`. This - example is taken from Example 1, p.121 of [BF05]_:: + Only return the divided-difference coefficients `F_{i,i}`. + This example is taken from Example 1, page 121 of [BF05]_:: sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), (1.9, 0.2818186), (2.2, 0.1103623)] - sage: R = PolynomialRing(QQ, "x") + sage: R = PolynomialRing(RR, "x") sage: R.divided_difference(points) - [0.765197700000000, -0.483705666666666, -0.108733888888889, @@ -1621,9 +1613,8 @@ def divided_difference(self, points, full_table=False): Now return the full divided-difference table:: sage: points = [(1.0, 0.7651977), (1.3, 0.6200860), (1.6, 0.4554022), (1.9, 0.2818186), (2.2, 0.1103623)] - sage: R = PolynomialRing(QQ, "x") + sage: R = PolynomialRing(RR, "x") sage: R.divided_difference(points, full_table=True) - [[0.765197700000000], [0.620086000000000, -0.483705666666666], [0.455402200000000, -0.548946000000000, -0.108733888888889], @@ -1637,14 +1628,14 @@ def divided_difference(self, points, full_table=False): 0.0680685185185209, 0.00182510288066044]] - The following example is taken from Example 4.12, p.225 of [MF99]_:: + The following example is taken from Example 4.12, page 225 of + [MF99]_:: sage: points = [(1, -3), (2, 0), (3, 15), (4, 48), (5, 105), (6, 192)] - sage: R = PolynomialRing(RR, "x") + sage: R = PolynomialRing(QQ, "x") sage: R.divided_difference(points) [-3, 3, 6, 1, 0, 0] sage: R.divided_difference(points, full_table=True) - [[-3], [0, 3], [15, 15, 6], @@ -1652,12 +1643,14 @@ def divided_difference(self, points, full_table=False): [105, 57, 12, 1, 0], [192, 87, 15, 1, 0, 0]] - REFERENCES: - .. [MF99] J.H. Mathews and K.D. Fink. *Numerical Methods Using MATLAB*. - 3rd edition, Prentice-Hall, 1999. + .. [MF99] J.H. Mathews and K.D. Fink. *Numerical Methods Using + MATLAB*. 3rd edition, Prentice-Hall, 1999. + """ + to_base_ring = self.base_ring().coerce + points = map(lambda x: map(to_base_ring, x), points) n = len(points) F = [[points[i][1]] for i in xrange(n)] for i in xrange(1, n): @@ -1671,48 +1664,51 @@ def divided_difference(self, points, full_table=False): return [F[i][i] for i in xrange(n)] def lagrange_polynomial(self, points, algorithm="divided_difference", previous_row=None): - """ - Return the Lagrange interpolation polynomial in ``self`` associated to - the given list of points. - - Given a list of points, i.e. tuples of elements of ``self``'s base - ring, this function returns the interpolation polynomial in the - Lagrange form. - + r""" + Return the Lagrange interpolation polynomial through the + given points. INPUT: - - ``points`` -- a list of tuples representing points through which - the polynomial returned by this function must pass. - - - ``algorithm`` -- (default: ``'divided_difference'``) the available - values for this option are ``'divided_difference'`` and ``neville``. + - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), + \dots, (x_n, y_n)` of elements of the base ring of ``self``, + where `x_i \neq x_j` for `i \neq j`. + + - ``algorithm`` -- (default: ``'divided_difference'``): one of + the following: + + - ``'divided_difference'``: use the method of divided + differences. + + - ``algorithm='neville'``: adapt Neville's method as + described on page 144 of [BF05]_ to recursively generate + the Lagrange interpolation polynomial. Neville's method + generates a table of approximating polynomials, where the + last row of that table contains the `n`-th Lagrange + interpolation polynomial. The adaptation implemented by + this method is to only generate the last row of this + table, instead of the full table itself. Generating the + full table can be memory inefficient. + + - ``previous_row`` -- (default: ``None``): This option is only + relevant if used with ``algorithm='neville'``. If provided, + this should be the last row of the table resulting from a + previous use of Neville's method. If such a row is passed, + then ``points`` should consist of both previous and new + interpolating points. Neville's method will then use that + last row and the interpolating points to generate a new row + containing an interpolation polynomial for the new points. - - If ``algorithm='divided_difference'`` then use the method of - divided difference. - - - If ``algorithm='neville'`` then adapt Neville's method as described - on page 144 of [BF05]_ to recursively generate the Lagrange - interpolation polynomial. Neville's method generates - a table of approximating polynomials, where the last row of that - table contains the `n`-th Lagrange interpolation polynomial. The - adaptation implemented by this method is to only generate the - last row of this table, instead of the full table itself. - Generating the full table can be memory inefficient. - - - ``previous_row`` -- (default: ``None``) This option is only relevant - if used together with ``algorithm='neville'``. If provided, this - should be the last row of the table resulting from a previous use of - Neville's method. If such a row is passed in, then ``points`` should - consist of both previous and new interpolating points. Neville's - method will then use that last row and the interpolating points to - generate a new row which contains a better Lagrange interpolation - polynomial. + OUTPUT: + The Lagrange interpolation polynomial through the points + `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)`. This is the + unique polynomial `P_n` of degree at most `n` satisfying + `P_n(x_i) = y_i` for `0 \le i \le n`. EXAMPLES: - By default, we use the method of divided-difference:: + By default, we use the method of divided differences:: sage: R = PolynomialRing(QQ, 'x') sage: f = R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)]); f @@ -1740,7 +1736,6 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r sage: R = PolynomialRing(QQ, 'x') sage: R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)], algorithm="neville") - [9, -11/7*x + 19/7, -17/42*x^2 - 83/42*x + 53/7, @@ -1750,8 +1745,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r sage: R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)], algorithm="neville") [a^2 + a + 1, x + a + 1, a^2*x^2 + a^2*x + a^2] - Repeated use of Neville's method to get better Lagrange interpolation - polynomials:: + Repeated use of Neville's method to get better Lagrange + interpolation polynomials:: sage: R = PolynomialRing(QQ, 'x') sage: p = R.lagrange_polynomial([(0,1),(2,2)], algorithm="neville") @@ -1763,11 +1758,10 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r sage: R.lagrange_polynomial([(a^2+a,a),(a,1),(a^2,a^2+a+1)], algorithm="neville", previous_row=p)[-1] a^2*x^2 + a^2*x + a^2 - TESTS: - The value for ``algorithm`` must be either ``'divided_difference'`` (by - default it is), or ``'neville'``:: + The value for ``algorithm`` must be either + ``'divided_difference'`` (default), or ``'neville'``:: sage: R = PolynomialRing(QQ, "x") sage: R.lagrange_polynomial([(0,1),(2,2),(3,-2),(-4,9)], algorithm="abc") @@ -1783,9 +1777,10 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r ... ValueError: algorithm must be one of 'divided_difference' or 'neville' - Make sure that ticket #10304 is fixed. The return value should always - be an element of ``self`` in the case of ``divided_difference``, or - a list of elements of ``self`` in the case of ``neville``. :: + Make sure that :trac:`10304` is fixed. The return value + should always be an element of ``self`` in the case of + ``divided_difference``, or a list of elements of ``self`` in + the case of ``neville``:: sage: R = PolynomialRing(QQ, "x") sage: R.lagrange_polynomial([]).parent() == R @@ -1799,12 +1794,21 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r sage: all(poly.parent() == R for poly in row) True + Check that base fields of positive characteristic are treated + correctly (see :trac:`9787`):: + + sage: R. = GF(101)[] + sage: R.lagrange_polynomial([[1, 0], [2, 0], [3, 0]]) + 0 REFERENCES: .. [BF05] R.L. Burden and J.D. Faires. *Numerical Analysis*. - Thomson Brooks/Cole, 8th edition, 2005. + 8th edition, Thomson Brooks/Cole, 2005. + """ + to_base_ring = self.base_ring().coerce + points = map(lambda x: map(to_base_ring, x), points) var = self.gen() # use the method of divided-difference @@ -1818,7 +1822,7 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r return self.zero() F = self.divided_difference(points) - P = self(F[n-1]) + P = self.coerce(F[n-1]) for i in xrange(n-2, -1, -1): P *= (var - points[i][0]) P += F[i] @@ -1847,7 +1851,7 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r P = previous_row + [None] * (N - M) # use results of previous computation if available Q = [None] * N for i in xrange(M, N): - Q[0] = self(points[i][1]) # start populating the current row + Q[0] = self.coerce(points[i][1]) # start populating the current row for j in xrange(1, 1 + i): numer = (var - points[i - j][0]) * Q[j - 1] - (var - points[i][0]) * P[j - 1] denom = points[i][0] - points[i - j][0] From 57f432cfe194c56c1b258a2d37046d67b15b82ab Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 18 Aug 2014 14:35:51 +0100 Subject: [PATCH 042/665] Trac 9787: use conversion instead of coercion to fix a doctest --- src/sage/rings/polynomial/polynomial_ring.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 828a7df8a12..c196a2f8f39 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1807,7 +1807,12 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r 8th edition, Thomson Brooks/Cole, 2005. """ - to_base_ring = self.base_ring().coerce + # Perhaps we should be slightly stricter on the input and use + # self.base_ring().coerce here (as in the divided_difference() + # method above). However, this breaks an example in + # sage.tests.french_book.nonlinear_doctest where the base ring + # is CC, but the function values lie in the symbolic ring. + to_base_ring = self.base_ring() points = map(lambda x: map(to_base_ring, x), points) var = self.gen() From e42ce551e66ff3f854c2424561bc71a075bac67a Mon Sep 17 00:00:00 2001 From: Dmitrii Pasechnik Date: Mon, 18 Aug 2014 21:10:02 +0100 Subject: [PATCH 043/665] instanc/tiated... --- src/sage/numerical/linear_functions.pyx | 4 ++-- src/sage/numerical/linear_tensor_constraints.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index a1689c92a2e..6bc51cbd34a 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -1001,7 +1001,7 @@ cdef class LinearConstraintsParent_class(Parent): .. warning:: - This class has no reason to be instanciated by the user, and + This class has no reason to be instantiated by the user, and is meant to be used by instances of :class:`MixedIntegerLinearProgram`. Also, use the :func:`LinearConstraintsParent` factory function. @@ -1190,7 +1190,7 @@ cdef class LinearConstraint(Element): .. warning:: - This class has no reason to be instanciated by the user, and + This class has no reason to be instantiated by the user, and is meant to be used by instances of :class:`MixedIntegerLinearProgram`. diff --git a/src/sage/numerical/linear_tensor_constraints.py b/src/sage/numerical/linear_tensor_constraints.py index a973c37277a..177a3abbc13 100644 --- a/src/sage/numerical/linear_tensor_constraints.py +++ b/src/sage/numerical/linear_tensor_constraints.py @@ -123,7 +123,7 @@ class LinearTensorConstraint(Element): .. warning:: - This class has no reason to be instanciated by the user, and + This class has no reason to be instantiated by the user, and is meant to be used by instances of :class:`MixedIntegerLinearProgram`. From 68ce711a9ab7f5d0a972d8b6443e1fece4bc49e9 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 25 Aug 2014 12:39:10 +0100 Subject: [PATCH 044/665] Trac 9787: use conversion into the base ring, clarify documentation --- src/sage/rings/polynomial/polynomial_ring.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index c196a2f8f39..d4ddcf89193 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1577,7 +1577,8 @@ def divided_difference(self, points, full_table=False): - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)` of elements of the base ring of ``self``, - where `x_i \neq x_j` for `i \neq j`. + where `x_i - x_j` is invertible for `i \neq j`. This method + converts the `x_i` and `y_i` into the base ring of `self`. - ``full_table`` -- boolean (default: ``False``): If ``True``, return the full divided-difference table. If ``False``, @@ -1590,7 +1591,7 @@ def divided_difference(self, points, full_table=False): Lagrange interpolation polynomial `P_n(x)` that passes through the points in ``points`` (see :meth:`lagrange_polynomial`). These are the coefficients `F_{0,0}, F_{1,1}, \dots, `F_{n,n}` - such that + in the base ring of ``self`` such that .. math:: @@ -1649,7 +1650,7 @@ def divided_difference(self, points, full_table=False): MATLAB*. 3rd edition, Prentice-Hall, 1999. """ - to_base_ring = self.base_ring().coerce + to_base_ring = self.base_ring() points = map(lambda x: map(to_base_ring, x), points) n = len(points) F = [[points[i][1]] for i in xrange(n)] @@ -1672,7 +1673,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r - ``points`` -- a list of pairs `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)` of elements of the base ring of ``self``, - where `x_i \neq x_j` for `i \neq j`. + where `x_i - x_j` is invertible for `i \neq j`. This method + converts the `x_i` and `y_i` into the base ring of `self`. - ``algorithm`` -- (default: ``'divided_difference'``): one of the following: @@ -1703,8 +1705,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r The Lagrange interpolation polynomial through the points `(x_0, y_0), (x_1, y_1), \dots, (x_n, y_n)`. This is the - unique polynomial `P_n` of degree at most `n` satisfying - `P_n(x_i) = y_i` for `0 \le i \le n`. + unique polynomial `P_n` of degree at most `n` in ``self`` + satisfying `P_n(x_i) = y_i` for `0 \le i \le n`. EXAMPLES: @@ -1808,8 +1810,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r """ # Perhaps we should be slightly stricter on the input and use - # self.base_ring().coerce here (as in the divided_difference() - # method above). However, this breaks an example in + # self.base_ring().coerce here and in the divided_difference() + # method above. However, this breaks an example in # sage.tests.french_book.nonlinear_doctest where the base ring # is CC, but the function values lie in the symbolic ring. to_base_ring = self.base_ring() From f01ecd13d99a669f0f153639223dd31aaf77ad72 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:04:59 +0200 Subject: [PATCH 045/665] orthogonal idempotents for all finitedimensional algebras with basis --- .../finite_dimensional_algebras_with_basis.py | 2 +- src/sage/categories/semisimple_algebras.py | 313 +++++++++--------- 2 files changed, 162 insertions(+), 153 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index c3aee19cbeb..8a613ef52f4 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -349,7 +349,7 @@ def center(self): center.rename("Center of {}".format(self)) return center - def orthogonal_idempotent(self): + def orthogonal_idempotents(self): r""" Return a maximal family of orthogonal idempotents of ``self``. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 5bfafd73b44..019f746455a 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -57,155 +57,164 @@ def super_categories(self): R = self.base_ring() return [Algebras(R)] - class ParentMethods: - - @cached_method - def orthogonal_idempotents(self): - r""" - Return a maximal list of orthogonal idempotents of ``self``. - - INPUT: - - - ``self`` -- semisimple algebra - - EXAMPLES:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: orth3 = A3.orthogonal_idempotents() - sage: sorted(orth3, key=str) - [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + - 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], - 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] - - :: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path - algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field - sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.orthogonal_idempotents() - sage: sorted(orth, key=str) - [B['x'], B['y']] - """ - Z = self.center() - orth = Z.orthogonal_idempotents() - return [x.lift() for x in orth] - - - class Commutative(CategoryWithAxiom_over_base_ring): - - class ParentMethods: - - @cached_method - def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): - r""" - Decompose a commutative finite dimensional semi-simple algebra - ``A`` into a direct sum of simple A-modules. - - INPUT: - - - ``self`` a finite dimensional semisimple commutative algebra. - - OUTPUT: - - - list of elements of ``self`` each generating a simple - submodule of ``self`` in direct sum with the others. The list - is maximal. - - Return a list of generators of simple A-modules. - - EXAMPLES: - - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: gens = Z5._semi_simple_commutative_decomposition_generators() - sage: sorted(gens, key=str) - [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] - + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], B[0] - 1/2*B[1] - + 1/4*B[3] + 1/4*B[4] - 1/4*B[6], B[0] - 1/3*B[2] + - 1/6*B[6], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] - + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6]] - """ - #Terminal case and stuffs - if listGen==None: - listGen = self.basis().list() - if self.dimension() == 1: - if topLevel: - return self.basis().list() - else: - return [x.lift() for x in self.basis()] - - #Searching for a good generator... - res = [] - B = self.basis() - while len(res)<2: - if listGen==[]: - raise Exception("Unable to fully decompose...") - curGen = listGen[ZZ.random_element(len(listGen))] - listGen.remove(curGen) - phi = self.module_morphism(on_basis=lambda i: - curGen*B[i], - codomain=self, - triangular=True) - aMat = phi.matrix(self.base_ring()) - res = aMat.eigenspaces_right() - - #Gotcha! Let's settle the algebra... - - res = [vector_space for _,vector_space in res] - res = [[self.from_vector(vector) for vector in eigenspace.basis()] - for eigenspace in res] - - decomp = [self.submodule(v, - category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] - - #Recursive on decomp - res = [x for space in decomp for x in - space._semi_simple_commutative_decomposition_generators(topLevel=False)] - if topLevel: - return res - else: - return map( lambda x: x.lift(), res) - - @cached_method - def orthogonal_idempotents(self): - r""" - Return the minimal orthogonal idempotents of ``self``. - - INPUT:: - - - ``self`` a commutative semisimple algebra - - OUTPUT:: - - - list of idempotents of ``self`` - - EXAMPLES:: - - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: orth = Z5.orthogonal_idempotents() - sage: orth = Z5.orthogonal_idempotents() - sage: sorted(orth, key=str) - [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + - 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + 1/30*B[3] - + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - 1/10*B[2] + 1/20*B[6], - 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - - 1/24*B[4] + 1/24*B[5]] - sage: orth[2] * orth[4] - 0 - sage: orth[1] ** 2 == orth[1] - True - """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in - self._semi_simple_commutative_decomposition_generators()] + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + + class WithBasis(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def orthogonal_idempotents(self): + r""" + Return a maximal list of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- semisimple algebra + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: orth3 = A3.orthogonal_idempotents() + sage: sorted(orth3, key=str) + [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], + 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + + :: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: sorted(orth, key=str) + [B['x'], B['y']] + """ + Z = self.center() + orth = Z.orthogonal_idempotents() + return [x.lift() for x in orth] + + + class Commutative(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): + r""" + Decompose a commutative finite dimensional semi-simple + algebra ``A`` into a direct sum of simple A-modules. + + INPUT: + + - ``self`` a finite dimensional semisimple commutative + algebra. + + OUTPUT: + + - list of elements of ``self`` each generating a simple + submodule of ``self`` in direct sum with the others. + The list is maximal. + + Return a list of generators of simple A-modules. + + EXAMPLES: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: sorted(gens, key=str) + [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], + B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - + 1/5*B[5], B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + + B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - + 1/4*B[6], B[0] - 1/3*B[2] + 1/6*B[6], B[0] - + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + + B[6]] + """ + #Terminal case and stuffs + if listGen==None: + listGen = self.basis().list() + if self.dimension() == 1: + if topLevel: + return self.basis().list() + else: + return [x.lift() for x in self.basis()] + + #Searching for a good generator... + res = [] + B = self.basis() + while len(res)<2: + if listGen==[]: + raise Exception("Unable to fully decompose...") + curGen = listGen[ZZ.random_element(len(listGen))] + listGen.remove(curGen) + phi = self.module_morphism(on_basis=lambda i: + curGen*B[i], + codomain=self, + triangular=True) + aMat = phi.matrix(self.base_ring()) + res = aMat.eigenspaces_right() + + #Gotcha! Let's settle the algebra... + + res = [vector_space for _,vector_space in res] + res = [[self.from_vector(vector) for vector in eigenspace.basis()] + for eigenspace in res] + + decomp = [self.submodule(v, + category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] + + #Recursive on decomp + res = [x for space in decomp for x in + space._semi_simple_commutative_decomposition_generators(topLevel=False)] + if topLevel: + return res + else: + return map( lambda x: x.lift(), res) + + @cached_method + def orthogonal_idempotents(self): + r""" + Return the minimal orthogonal idempotents of ``self``. + + INPUT:: + + - ``self`` a commutative semisimple algebra + + OUTPUT:: + + - list of idempotents of ``self`` + + EXAMPLES:: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: orth = Z5.orthogonal_idempotents() + sage: orth = Z5.orthogonal_idempotents() + sage: sorted(orth, key=str) + [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] + - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + + 1/30*B[3] + - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + + 1/30*B[3] + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - + 1/10*B[2] + 1/20*B[6], 5/24*B[0] + 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], + 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - + 1/24*B[4] + 1/24*B[5]] + sage: orth[2] * orth[4] + 0 + sage: orth[1] ** 2 == orth[1] + True + """ + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in + self._semi_simple_commutative_decomposition_generators()] From 57fbdc00054e7604f933eb89a443fd425f45361a Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:08:10 +0200 Subject: [PATCH 046/665] doctest --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 8a613ef52f4..a8c4d5330be 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -364,7 +364,7 @@ def orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotent() + sage: A.orthogonal_idempotents() [y, x] """ Aquo = self.semisimple_quotient() From aa1a19ccbb2879e88c9403e14023bcefbe808cdf Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:34:09 +0200 Subject: [PATCH 047/665] example lift_idempotent --- src/sage/categories/algebras.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 4044a04f94e..33afc2987e7 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -128,13 +128,10 @@ def _lift_idempotent(self): EXAMPLES:: - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: Z3 = A3.center() - sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z3.orthogonal_idempotents() - sage: x = orth[2]._lift_idempotent() - sage: x not in Z3 and x in A3 - True + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example().semisimple_quotient() + sage: orth = A.orthogonal_idempotents() + sage: orth[1]._lift_idempotent() + x TODO: better documentation. """ From d107ce1674e167f22872841da47e548ca0a15872 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:13:00 +0200 Subject: [PATCH 048/665] Cartan invariant matrix for general finite dimension algebras with basis --- .../finite_dimensional_algebras_with_basis.py | 65 +++++++++++++++++++ src/sage/categories/semisimple_algebras.py | 10 +-- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index a8c4d5330be..25f14829f6d 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -16,6 +16,9 @@ from sage.categories.algebras import Algebras from sage.categories.associative_algebras import AssociativeAlgebras from sage.categories.semisimple_algebras import SemisimpleAlgebras +from sage.matrix.constructor import Matrix +from sage.functions.other import sqrt + class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): r""" @@ -349,6 +352,33 @@ def center(self): center.rename("Center of {}".format(self)) return center + def ideal(self, a, side='left'): + r""" + Construct the ``left`` or ``right`` A-module generated by ``a``. + + EXAMPLE:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.ideal(A.an_element()) + Free module generated by {0, 1, 2, 3} over Rational Field + + """ + B = self.basis() + if side == 'left': + phi = self.module_morphism(on_basis=lambda i: a*B[i], + codomain=self, + triangular=True) + elif side == 'right': + phi = self.module_morphism(on_basis=lambda i: B[i]*a, + codomain=self, + triangluar=True) + else: + raise Exception("Side must be ``left`` or ``right``") + ideal = phi.matrix().image() + #now let's make it a submodule of A + return self.submodule([self.from_vector(v) for v in ideal.basis()], + already_echelonized=True) + def orthogonal_idempotents(self): r""" Return a maximal family of orthogonal idempotents of ``self``. @@ -371,6 +401,41 @@ def orthogonal_idempotents(self): orth_quo = Aquo.orthogonal_idempotents() return [x._lift_idempotent() for x in orth_quo] + @cached_method + def cartan_invariant_matrix(self, side='left'): + r""" + Return the Cartan invariant matrix of the algebra ``self``. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.cartan_invariant_matrix() + [1 0] + [2 1] + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: A3.cartan_invariant_matrix() + [1 0 0] + [0 1 0] + [0 0 1] + + """ + Aquo = self.semisimple_quotient() + orth_quo = Aquo.orthogonal_idempotents() + # Dimension of simple modules + dimSimples = [sqrt(Aquo.ideal(e, side).dimension()) for e in + orth_quo] + orth = [x._lift_idempotent() for x in orth_quo] + return Matrix(self.base_ring(), + len(orth), + lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + + def _cartan_matrix_coef(self, ei, ej): + B = self.basis() + phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, + codomain=self, + triangular=True) + return phi.matrix().rank() + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 019f746455a..a1d317610dd 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -179,7 +179,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev return map( lambda x: x.lift(), res) @cached_method - def orthogonal_idempotents(self): + def orthogonal_idempotents(self, dimSimple=False): r""" Return the minimal orthogonal idempotents of ``self``. @@ -193,11 +193,9 @@ def orthogonal_idempotents(self): EXAMPLES:: - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) + sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() sage: orth = Z5.orthogonal_idempotents() - sage: orth = Z5.orthogonal_idempotents() sage: sorted(orth, key=str) [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] @@ -215,6 +213,4 @@ def orthogonal_idempotents(self): sage: orth[1] ** 2 == orth[1] True """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in - self._semi_simple_commutative_decomposition_generators()] + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] From 9486c194cd14207c0135368f3ea1c7102d808f48 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:35:59 +0200 Subject: [PATCH 049/665] projective modules --- .../finite_dimensional_algebras_with_basis.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 25f14829f6d..505082e426a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -429,6 +429,22 @@ def cartan_invariant_matrix(self, side='left'): len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + def projective_modules(self, side='left'): + r""" + Return the list of indecomposable projective ``side``-sided + ``self``-modules. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: projs = A.projective_modules() + sage: sorted(projs, key=str) + [Free module generated by {0, 1, 2} over Rational Field, + Free module generated by {0} over Rational Field] + """ + return [self.ideal(e, side) for e in self.orthogonal_idempotents()] + + def _cartan_matrix_coef(self, ei, ej): B = self.basis() phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, From 4efa87753fc20a4fee508943e55c45aa83f03ee2 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:53:20 +0200 Subject: [PATCH 050/665] projective decomposition --- .../finite_dimensional_algebras_with_basis.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 505082e426a..13f7ac90f5e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -429,7 +429,7 @@ def cartan_invariant_matrix(self, side='left'): len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) - def projective_modules(self, side='left'): + def projective_decomposition(self, side='left'): r""" Return the list of indecomposable projective ``side``-sided ``self``-modules. @@ -437,10 +437,17 @@ def projective_modules(self, side='left'): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_modules() + sage: projs = A.projective_decomposition() sage: sorted(projs, key=str) [Free module generated by {0, 1, 2} over Rational Field, Free module generated by {0} over Rational Field] + + We check that the sum of the dimensions of the indecomposable + projective module is the dimension of ``self``: + + sage: sum([P.dimension() for P in projs]) == A.dimension() + True + """ return [self.ideal(e, side) for e in self.orthogonal_idempotents()] From 9c4d13de5cdd810818d23175a39e77ff496a12f1 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 16:44:41 +0200 Subject: [PATCH 051/665] 11111: revert subobjects of algebras --- src/sage/categories/algebras.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 64240264157..143612c7add 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -217,26 +217,3 @@ def extra_super_categories(self): """ from sage.categories.coalgebras import Coalgebras return [Coalgebras(self.base_category().base_ring())] - class Subobjects(SubobjectsCategory): - - class ElementMethods: - - def _mul_(self, right): - r""" - Product of two elements. - INPUT:: - - - ``self``, ``right`` -- two elements - - If B is a SubModuleWithBasis of A, then the multiplication law of B is - inherited from the multiplication of A. - - EXAMPLES:: - - sage: Z = SymmetricGroup(5).algebra(QQ).center() - sage: B = Z.basis() - sage: B[3] * B[2] - 4*B[2] + 6*B[3] + 5*B[6] - """ - p = self.parent() - return p.retract( self.lift() * right.lift()) From d1fc0a9aa9a77363de6e8beaed205fdcaee7feb9 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 16:45:21 +0200 Subject: [PATCH 052/665] 11111: the center of a semisimple algebra is semisimple. --- .../categories/finite_dimensional_algebras_with_basis.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 9526742362c..46bdb05703b 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -326,6 +326,8 @@ def center(self): True sage: [c.lift() for c in center.basis()] [x + y] + sage: DihedralGroup(6).algebra(QQ).center() in SemisimpleAlgebras + True .. TODO:: @@ -336,7 +338,9 @@ def center(self): sage: TestSuite(center).run() """ - category = Algebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() + category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() + if self in SemisimpleAlgebras: + category = category & SemisimpleAlgebras(self.base_ring()) center = self.submodule(self.center_basis(), category = category, already_echelonized = True) From 7cbeb9a0b9a5ba10d7933260d20be29c9f0935fb Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 18:14:26 +0200 Subject: [PATCH 053/665] 16659: renamed, moved some methods to better places --- src/sage/categories/algebras.py | 25 ------- .../finite_dimensional_algebras_with_basis.py | 69 ++++++++++++++++--- src/sage/categories/semisimple_algebras.py | 14 ++-- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index ba7102b1cb7..143612c7add 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -119,31 +119,6 @@ def _div_(self, y): class Quotients(QuotientsCategory): - class ElementMethods: - - def _lift_idempotent(self): - r""" - Lift an idempotent of parent of ``self`` into an indempotent of - parent of ``self.lift()`` - - EXAMPLES:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example().semisimple_quotient() - sage: orth = A.orthogonal_idempotents() - sage: orth[1]._lift_idempotent() - x - - TODO: better documentation. - """ - idempOld = None - idemp = self.lift() - p = idemp.parent() - while idemp <> idempOld: - tmp = idemp - idemp = (p.one() - (p.one() - idemp**2)**2) - idempOld = tmp - return idemp - class ParentMethods: def algebra_generators(self): diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 22a90c9f5dd..033fbd0d6d4 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -151,7 +151,7 @@ def radical_basis(self, cache_products=True): from sage.modules.free_module_element import vector if self in SemisimpleAlgebras(self.base_ring()): - return self.from_vector(vector(self.zero())) + return [] if cache_products is True: product_on_basis = cached_function(self.product_on_basis) @@ -353,14 +353,14 @@ def center(self): center.rename("Center of {}".format(self)) return center - def ideal(self, a, side='left'): + def principal_ideal(self, a, side='left'): r""" - Construct the ``left`` or ``right`` A-module generated by ``a``. + Construct the ``side`` A-module generated by ``a``. EXAMPLE:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.ideal(A.an_element()) + sage: A.principal_ideal(A.an_element()) Free module generated by {0, 1, 2, 3} over Rational Field """ @@ -395,12 +395,50 @@ def orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents() - [y, x] + sage: sorted(A.orthogonal_idempotents(), key=str) + [x, y] + sage: Monoids().Finite().example() + An example of a finite multiplicative monoid: the integers + modulo 12 + sage: Z12 = Monoids().Finite().example() + sage: A = Z12.algebra(QQ) + sage: sorted(A.orthogonal_idempotents(), key=str) + [-1/2*B[3] + 1/2*B[9], -1/2*B[8] + 1/2*B[4], -B[0] + 1/2*B[3] + + 1/2*B[9], 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/2*B[3] + + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/4*B[1] + 1/4*B[11] + - 1/4*B[5] - 1/4*B[7], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + + 1/2*B[8] - 1/4*B[11], B[0], B[0] + 1/4*B[1] - 1/2*B[3] - + 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + + 1/4*B[11]] + + """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() - return [x._lift_idempotent() for x in orth_quo] + return [self._lift_idempotent(x) for x in orth_quo] + + def _lift_idempotent(self, x): + r""" + Lift an idempotent of the semisimple quotient of ``self`` into an + idempotent of ``self``. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: A._lift_idempotent(orth[1]) + y + """ + idempOld = None + assert x in self.semisimple_quotient() + idemp = x.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp @cached_method def cartan_invariant_matrix(self, side='left'): @@ -418,12 +456,23 @@ def cartan_invariant_matrix(self, side='left'): [1 0 0] [0 1 0] [0 0 1] - + sage: Z12 = Monoids().Finite().example() + sage: A = Z12.algebra(QQ) + sage: A.cartan_invariant_matrix() + [1 0 0 0 0 0 0 0 0] + [0 1 0 0 0 0 0 0 0] + [0 0 2 0 0 0 0 0 0] + [0 0 0 1 0 0 0 0 0] + [0 0 0 0 1 0 0 0 0] + [0 0 0 0 0 2 0 0 0] + [0 0 0 0 0 0 1 0 0] + [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 0 2] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() # Dimension of simple modules - dimSimples = [sqrt(Aquo.ideal(e, side).dimension()) for e in + dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] orth = [x._lift_idempotent() for x in orth_quo] return Matrix(self.base_ring(), @@ -450,7 +499,7 @@ def projective_decomposition(self, side='left'): True """ - return [self.ideal(e, side) for e in self.orthogonal_idempotents()] + return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents()] def _cartan_matrix_coef(self, ei, ej): diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index a1d317610dd..9654626a51c 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -93,9 +93,8 @@ def orthogonal_idempotents(self): sage: sorted(orth, key=str) [B['x'], B['y']] """ - Z = self.center() - orth = Z.orthogonal_idempotents() - return [x.lift() for x in orth] + return [x.lift() + for x in self.center().orthogonal_idempotents()] class Commutative(CategoryWithAxiom_over_base_ring): @@ -103,7 +102,7 @@ class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): + def _orthogonal_decomposition(self, listGen=None, topLevel=True): r""" Decompose a commutative finite dimensional semi-simple algebra ``A`` into a direct sum of simple A-modules. @@ -126,7 +125,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: gens = Z5._orthogonal_decomposition() sage: sorted(gens, key=str) [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - @@ -172,7 +171,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev #Recursive on decomp res = [x for space in decomp for x in - space._semi_simple_commutative_decomposition_generators(topLevel=False)] + space._orthogonal_decomposition(topLevel=False)] if topLevel: return res else: @@ -213,4 +212,5 @@ def orthogonal_idempotents(self, dimSimple=False): sage: orth[1] ** 2 == orth[1] True """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for + e in self._orthogonal_decomposition()] From b6dc4b989f9a749f7e1dc9a58180d04bada88e30 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 19:12:42 +0200 Subject: [PATCH 054/665] typos --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 033fbd0d6d4..031864eb6c1 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -474,7 +474,7 @@ def cartan_invariant_matrix(self, side='left'): # Dimension of simple modules dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] - orth = [x._lift_idempotent() for x in orth_quo] + orth = [self._lift_idempotent(x) for x in orth_quo] return Matrix(self.base_ring(), len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) From 479fddb4afe86e8dc5382f50e0d8d0d11913e23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 3 Sep 2014 13:55:23 +0200 Subject: [PATCH 055/665] 16925: revert SymmetricGroups(...).algebra(...) to just do the standard thing --- src/sage/groups/perm_gps/permgroup_named.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index b1ced7128ff..ff48fe16c02 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -424,19 +424,6 @@ def major_index(self, parameter=None): from sage.combinat.q_analogues import q_factorial return q_factorial(self.degree(), parameter) - def algebra(self, base_ring): - """ - Return the symmetric group algebra associated to ``self``. - - EXAMPLES:: - - sage: S4 = SymmetricGroup(4) - sage: S4.algebra(QQ) - Symmetric group algebra of order 4 over Rational Field - """ - from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra - return SymmetricGroupAlgebra(base_ring, len(self._domain)) - class AlternatingGroup(PermutationGroup_symalt): def __init__(self, domain=None): """ From ce71c7444f957da20f6f9bd1cda95fde8feda9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 3 Sep 2014 14:38:01 +0200 Subject: [PATCH 056/665] 16925: updated a few doctests according to the previous commit --- src/sage/categories/groups.py | 9 --------- .../combinat/root_system/hecke_algebra_representation.py | 5 ++--- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 59b83017220..d8810580dcf 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -608,15 +608,6 @@ def algebra_generators(self): sage: GroupAlgebras(QQ).example(AlternatingGroup(10)).algebra_generators() Finite family {(1,2,3,4,5,6,7,8,9): B[(1,2,3,4,5,6,7,8,9)], (8,9,10): B[(8,9,10)]} - - .. NOTE:: - - This function is overloaded for SymmetricGroupAlgebras - to return Permutations and not Elements of the - symmetric group:: - - sage: GroupAlgebras(QQ).example(SymmetricGroup(10)).algebra_generators() - [[2, 1, 3, 4, 5, 6, 7, 8, 9, 10], [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]] """ from sage.sets.family import Family return Family(self.group().gens(), self.term) diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index fe4366dc3b5..bb01389fd13 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -79,8 +79,7 @@ def __init__(self, domain, on_basis, cartan_type, q1, q2, q=1, side="right"): sage: domain = W.algebra(QQ) sage: action = lambda x,i: domain.monomial(x.apply_simple_reflection(i, side="right")) sage: HeckeAlgebraRepresentation(domain, action, CartanType(["A",2]), 1, -1) - A representation of the (1, -1)-Hecke algebra of type ['A', 2] - on Symmetric group algebra of order 3 over Rational Field + A representation of the (1, -1)-Hecke algebra of type ['A', 2] on Group algebra of Symmetric group of order 3! as a permutation group over Rational Field """ self._domain = domain self._Ti_on_basis = on_basis @@ -227,7 +226,7 @@ def on_basis(self, x, word, signs=None, scalar=None): sage: rho = HeckeAlgebraRepresentation(domain, action, CartanType(["A",2]), 1, -1) sage: rho.on_basis(W.one(), (1,2,1)) - (1,3) + B[(1,3)] sage: word = (1,2) sage: u = W.from_reduced_word(word) From 60e314ca7b1185ff6eff78f9b8bf74883e059583 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 3 Sep 2014 15:27:03 +0200 Subject: [PATCH 057/665] undo a stupid error in finite_dimensional_modules_with_basis.matrix --- src/sage/categories/finite_dimensional_modules_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index f8baa5d150f..718f37bb301 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -273,7 +273,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis + on_basis = self.on_basis() basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) From 4a9ea8b0b7c0d2234512eb98d807a6c986d49fdf Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 09:31:06 +0200 Subject: [PATCH 058/665] 16659: took off randomness, doctest --- .../finite_dimensional_algebras_with_basis.py | 46 +++++++------- src/sage/categories/semisimple_algebras.py | 63 +++++++++---------- 2 files changed, 50 insertions(+), 59 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 031864eb6c1..6444cc5163d 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -391,27 +391,24 @@ def orthogonal_idempotents(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field - sage: sorted(A.orthogonal_idempotents(), key=str) - [x, y] - sage: Monoids().Finite().example() + and b:x->y) over Rational Field + sage: A.orthogonal_idempotents() + [y, x] + sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 - sage: Z12 = Monoids().Finite().example() sage: A = Z12.algebra(QQ) - sage: sorted(A.orthogonal_idempotents(), key=str) - [-1/2*B[3] + 1/2*B[9], -1/2*B[8] + 1/2*B[4], -B[0] + 1/2*B[3] + - 1/2*B[9], 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/2*B[3] + - 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/4*B[1] + 1/4*B[11] - - 1/4*B[5] - 1/4*B[7], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] - + 1/2*B[8] - 1/4*B[11], B[0], B[0] + 1/4*B[1] - 1/2*B[3] - - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + - 1/4*B[11]] - - + sage: A.orthogonal_idempotents() + [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - + 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], + 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - + 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - + 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + + 1/4*B[11]] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() @@ -428,7 +425,7 @@ def _lift_idempotent(self, x): sage: Aquo = A.semisimple_quotient() sage: orth = Aquo.orthogonal_idempotents() sage: A._lift_idempotent(orth[1]) - y + x """ idempOld = None assert x in self.semisimple_quotient() @@ -460,13 +457,13 @@ def cartan_invariant_matrix(self, side='left'): sage: A = Z12.algebra(QQ) sage: A.cartan_invariant_matrix() [1 0 0 0 0 0 0 0 0] - [0 1 0 0 0 0 0 0 0] - [0 0 2 0 0 0 0 0 0] + [0 2 0 0 0 0 0 0 0] + [0 0 1 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0 0] - [0 0 0 0 0 2 0 0 0] + [0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 1 0 0] - [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 2 0] [0 0 0 0 0 0 0 0 2] """ Aquo = self.semisimple_quotient() @@ -487,10 +484,9 @@ def projective_decomposition(self, side='left'): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_decomposition() - sage: sorted(projs, key=str) - [Free module generated by {0, 1, 2} over Rational Field, - Free module generated by {0} over Rational Field] + sage: projs = A.projective_decomposition(); projs + [Free module generated by {0} over Rational Field, + Free module generated by {0, 1, 2} over Rational Field] We check that the sum of the dimensions of the indecomposable projective module is the dimension of ``self``: diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 9654626a51c..d4e3f92ec2f 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -75,12 +75,12 @@ def orthogonal_idempotents(self): EXAMPLES:: sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: orth3 = A3.orthogonal_idempotents() - sage: sorted(orth3, key=str) - [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + - 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], - 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + sage: A3.orthogonal_idempotents() + [2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)], 1/6*B[()] + + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] + - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - + 1/6*B[(1,3)]] :: @@ -89,9 +89,8 @@ def orthogonal_idempotents(self): algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.orthogonal_idempotents() - sage: sorted(orth, key=str) - [B['x'], B['y']] + sage: Aquo.orthogonal_idempotents() + [B['y'], B['x']] """ return [x.lift() for x in self.center().orthogonal_idempotents()] @@ -125,19 +124,17 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: gens = Z5._orthogonal_decomposition() - sage: sorted(gens, key=str) - [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], - B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - - 1/5*B[5], B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + - B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - - 1/4*B[6], B[0] - 1/3*B[2] + 1/6*B[6], B[0] - - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + - 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + - B[6]] + sage: Z5._orthogonal_decomposition() + [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + + B[3] + B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] + - B[4] - B[5] + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - + 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] - 1/5*B[1] + + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + 1/5*B[5], B[0] + + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] - + 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] """ #Terminal case and stuffs - if listGen==None: + if listGen == None: listGen = self.basis().list() if self.dimension() == 1: if topLevel: @@ -151,8 +148,7 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): while len(res)<2: if listGen==[]: raise Exception("Unable to fully decompose...") - curGen = listGen[ZZ.random_element(len(listGen))] - listGen.remove(curGen) + curGen = listGen.pop() phi = self.module_morphism(on_basis=lambda i: curGen*B[i], codomain=self, @@ -195,18 +191,17 @@ def orthogonal_idempotents(self, dimSimple=False): sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() sage: orth = Z5.orthogonal_idempotents() - sage: sorted(orth, key=str) - [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + - 1/30*B[3] - - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + - 1/30*B[3] + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - - 1/10*B[2] + 1/20*B[6], 5/24*B[0] + 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], - 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - - 1/24*B[4] + 1/24*B[5]] + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - 1/120*B[5] + + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + + 1/24*B[5], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - + 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] sage: orth[2] * orth[4] 0 sage: orth[1] ** 2 == orth[1] From 496af7b1dd7cb3c2f828fd6eacb171254d24b757 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 09:35:58 +0200 Subject: [PATCH 059/665] 16659: typo + todo --- src/sage/categories/semisimple_algebras.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index d4e3f92ec2f..25aee74a6e8 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -119,7 +119,7 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): Return a list of generators of simple A-modules. - EXAMPLES: + EXAMPLES:: sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) @@ -132,6 +132,11 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] + + .. TODO:: + + Improve the function by only using matrix + operations. """ #Terminal case and stuffs if listGen == None: From 0576a8bb652706451039c6f79e194a42281cb488 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 18:35:01 +0200 Subject: [PATCH 060/665] 16659: Speedup radical_basis --- .../finite_dimensional_algebras_with_basis.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6444cc5163d..7a557f9b82b 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -159,11 +159,23 @@ def radical_basis(self, cache_products=True): product_on_basis = self.product_on_basis if p == 0: - keys = self.basis().keys() - mat = matrix(self.base_ring(), [ - [sum(product_on_basis(x,j).coefficient(i) * product_on_basis(y,i).coefficient(j) - for i in keys for j in keys) for x in keys] for y in keys - ]) + keys = list(self.basis().keys()) + # x[i,j] = product_on_basis(x,i).coefficient(j) + cache = [{(i,j): c + for i in keys + for j,c in product_on_basis(y,i)} + for y in keys] + mat = [ + [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) + for x in cache] + for y in cache] + + mat = matrix(self.base_ring(), mat) + # Old algorithm: + # mat = matrix(self.base_ring(), [ + # [sum(product_on_basis(x,j).coefficient(i) * c + # for i in keys for j,c in product_on_basis(y,i)) for x in keys] + # for y in keys ]) rad_basis = mat.kernel().basis() else: # TODO: some finite field elements in Sage have both an From 9e2e667f8ea2b09ada989107db34547acbc66f12 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 22 Jun 2014 23:20:12 +0200 Subject: [PATCH 061/665] display of numbers in tikz output --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index baed522eb18..1ab834b03a7 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1433,7 +1433,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1554,7 +1554,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1717,7 +1717,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str([i.n(digits=3) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From 3fd9d4d041ac0ca034609e6cd864619fdda6a04f Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 23 Jun 2014 10:07:35 +0200 Subject: [PATCH 062/665] fix tikz output for plot of projections of polytopes --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 1ab834b03a7..4d374634556 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1433,7 +1433,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str([(10^(-5)*floor(10^5*i)).n(4) for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1554,7 +1554,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1717,7 +1717,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(digits=4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From 60c0575f4c40fddf539586ccc75c423d1b722318 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 23 Jun 2014 10:14:36 +0200 Subject: [PATCH 063/665] forgot to change one line --- src/sage/geometry/polyhedron/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 4d374634556..da0be0ecd19 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1433,7 +1433,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str([(10^(-5)*floor(10^5*i)).n(4) for i in v]) + v_vect = str(['%.5f' % i for i in v]) v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect From caee91aaea2952e69bb32f083188f81b1385c2ef Mon Sep 17 00:00:00 2001 From: "moritz@math.fu-berlin.de" Date: Mon, 23 Jun 2014 12:58:53 +0200 Subject: [PATCH 064/665] corrected string formatting --- src/sage/geometry/polyhedron/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index da0be0ecd19..051f1d0427b 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1433,7 +1433,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[', '(') v_vect = v_vect.replace(']', ')') tag = '%s' %v_vect @@ -1554,7 +1554,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, edges = '' for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect @@ -1717,7 +1717,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, for vert in self.points: v = self.coords[vert] - v_vect = str(['%.5f' % i for i in v]) + v_vect = str(['%.5f' % i for i in v]).replace('\'','') v_vect = v_vect.replace('[','(') v_vect = v_vect.replace(']',')') tag = '%s' %v_vect From d58badcd0d0dd99808a7a62bbe7f4600bb1e0449 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 7 Dec 2014 14:13:22 +0100 Subject: [PATCH 065/665] added doctest to show that the problem is fixed --- src/sage/geometry/polyhedron/plot.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 051f1d0427b..f3b85155dae 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1420,7 +1420,13 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): back/.style={loosely dotted, thin}, edge/.style={color=black, thick}, sage: open('polytope-tikz2.tex', 'w').write(Image) # not tested - + + Scientific notation is not used in the output (Trac #16519):: + sage: P=Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) + sage: tikzstr=P.projection().tikz() + sage: 'e-10' in tikzstr + False + .. NOTE:: The ``facet_color`` is the filing color of the polytope (polygon). From dd9dbda7358dd74b9aead6841472dc08f1908a14 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 7 Dec 2014 14:18:31 +0100 Subject: [PATCH 066/665] corrected whitespace --- src/sage/geometry/polyhedron/plot.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index f3b85155dae..0a2c21a2231 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1420,13 +1420,13 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): back/.style={loosely dotted, thin}, edge/.style={color=black, thick}, sage: open('polytope-tikz2.tex', 'w').write(Image) # not tested - - Scientific notation is not used in the output (Trac #16519):: - sage: P=Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) - sage: tikzstr=P.projection().tikz() - sage: 'e-10' in tikzstr - False - + + Scientific notation is not used in the output (Trac #16519):: + sage: P=Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) + sage: tikzstr=P.projection().tikz() + sage: 'e-10' in tikzstr + False + .. NOTE:: The ``facet_color`` is the filing color of the polytope (polygon). From 30aea86aaa698271bf616225c25e24a1d17e13f2 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Sun, 7 Dec 2014 14:21:56 +0100 Subject: [PATCH 067/665] updated output of examples to more digits --- src/sage/geometry/polyhedron/plot.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 0a2c21a2231..091f608738a 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1543,7 +1543,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, sage: print '\n'.join(Img.splitlines()[21:25]) %% Drawing the interior %% - \fill[facet] (1.00, 0.000, 0.000) -- (0.000, 0.000, 1.00) -- (0.000, 1.00, 0.000) -- cycle {}; + \fill[facet] (1.00000, 0.00000, 0.00000) -- (0.00000, 0.00000, 1.00000) -- (0.00000, 1.00000, 0.00000) -- cycle {}; %% .. NOTE:: @@ -1670,15 +1670,15 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, sage: print '\n'.join(ImageAsso.splitlines()[29:41]) %% Drawing edges in the back %% - \draw[edge,back] (-0.500, -0.500, -0.500) -- (-1.00, 0.000, 0.000); - \draw[edge,back] (-0.500, -0.500, -0.500) -- (0.000, -1.00, 0.000); - \draw[edge,back] (-0.500, -0.500, -0.500) -- (0.000, 0.000, -1.00); - \draw[edge,back] (-1.00, 0.000, 0.000) -- (-1.00, 0.000, 1.00); - \draw[edge,back] (-1.00, 0.000, 0.000) -- (-1.00, 1.00, 0.000); - \draw[edge,back] (0.000, -1.00, 0.000) -- (0.000, -1.00, 1.00); - \draw[edge,back] (0.000, -1.00, 0.000) -- (1.00, -1.00, 0.000); - \draw[edge,back] (0.000, 0.000, -1.00) -- (0.000, 1.00, -1.00); - \draw[edge,back] (0.000, 0.000, -1.00) -- (1.00, 0.000, -1.00); + \draw[edge,back] (-0.50000, -0.50000, -0.50000) -- (-1.00000, 0.00000, 0.00000); + \draw[edge,back] (-0.50000, -0.50000, -0.50000) -- (0.00000, -1.00000, 0.00000); + \draw[edge,back] (-0.50000, -0.50000, -0.50000) -- (0.00000, 0.00000, -1.00000); + \draw[edge,back] (-1.00000, 0.00000, 0.00000) -- (-1.00000, 0.00000, 1.00000); + \draw[edge,back] (-1.00000, 0.00000, 0.00000) -- (-1.00000, 1.00000, 0.00000); + \draw[edge,back] (0.00000, -1.00000, 0.00000) -- (0.00000, -1.00000, 1.00000); + \draw[edge,back] (0.00000, -1.00000, 0.00000) -- (1.00000, -1.00000, 0.00000); + \draw[edge,back] (0.00000, 0.00000, -1.00000) -- (0.00000, 1.00000, -1.00000); + \draw[edge,back] (0.00000, 0.00000, -1.00000) -- (1.00000, 0.00000, -1.00000); %% """ view_vector = vector(RDF, view) From efb17937900549be9a969c8d94197e7c7e9719d1 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Tue, 9 Dec 2014 10:14:41 +0100 Subject: [PATCH 068/665] newline added --- src/sage/geometry/polyhedron/plot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 091f608738a..eadb5bc2238 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1421,7 +1421,9 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): edge/.style={color=black, thick}, sage: open('polytope-tikz2.tex', 'w').write(Image) # not tested - Scientific notation is not used in the output (Trac #16519):: + + Scientific notation is not used in the output (:trac:`16519`):: + sage: P=Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) sage: tikzstr=P.projection().tikz() sage: 'e-10' in tikzstr From 5b3c7d2fef8ad5e167a6609f72c41248629de954 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 28 Dec 2014 12:08:08 -0800 Subject: [PATCH 069/665] Implement incidence algebras. --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/posets/__init__.py | 2 + .../combinat/posets/incidence_algebras.py | 352 ++++++++++++++++++ src/sage/combinat/posets/posets.py | 15 + 4 files changed, 370 insertions(+) create mode 100644 src/sage/combinat/posets/incidence_algebras.py diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index e84dc84733e..e4a1d2a1d3b 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -153,6 +153,7 @@ Comprehensive Module list sage/combinat/posets/all sage/combinat/posets/elements sage/combinat/posets/hasse_diagram + sage/combinat/posets/incidence_algebras sage/combinat/posets/lattices sage/combinat/posets/linear_extensions sage/combinat/posets/poset_examples diff --git a/src/sage/combinat/posets/__init__.py b/src/sage/combinat/posets/__init__.py index 8b6b80ea2eb..3e5ec24c187 100644 --- a/src/sage/combinat/posets/__init__.py +++ b/src/sage/combinat/posets/__init__.py @@ -13,6 +13,8 @@ - :ref:`sage.combinat.posets.linear_extensions` +- :ref:`sage.combinat.posets.incidence_algebras` + - :ref:`sage.combinat.tamari_lattices` - :ref:`sage.combinat.interval_posets` diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py new file mode 100644 index 00000000000..248b288a530 --- /dev/null +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -0,0 +1,352 @@ +r""" +Incidence Algebras +""" +#***************************************************************************** +# Copyright (C) 2014 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# The full text of the GPL is available at: +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.categories.algebras import Algebras +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.combinat.free_module import CombinatorialFreeModule +from sage.matrix.matrix_space import MatrixSpace + +from copy import copy + +class IncidenceAlgebra(CombinatorialFreeModule): + r""" + The incidence algebra of a poset. + """ + def __init__(self, R, P, prefix='I'): + """ + Initialize ``self``. + + TESTS:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: TestSuite(I).run() + """ + cat = Algebras(R).WithBasis() + if P in FiniteEnumeratedSets(): + cat = cat.FiniteDimensional() + self._poset = P + CombinatorialFreeModule.__init__(self, R, map(tuple, P.intervals()), + prefix=prefix, category=cat) + + def _repr_term(self, A): + """ + Return a string representation of the term labeled by ``A``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I._repr_term((4, 12)) + 'I[4, 12]' + """ + return self.prefix() + str(list(A)) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: P.incidence_algebra(QQ) + Incidence algebra of Finite lattice containing 16 elements + over Rational Field + """ + return "Incidence algebra of {} over {}".format(self._poset, self.base_ring()) + + def poset(self): + """ + Return the defining poset of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I.poset() + Finite lattice containing 16 elements + sage: I.poset() == P + True + """ + return self._poset + + def product_on_basis(self, A, B): + r""" + Return the product of basis elements indexed by ``A`` and ``B``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I.product_on_basis((1, 3), (3, 11)) + I[1, 11] + sage: I.product_on_basis((1, 3), (2, 2)) + 0 + """ + if A[1] == B[0]: + return self.monomial((A[0], B[1])) + return self.zero() + + @cached_method + def one(self): + """ + Return the element `1` in ``self`` (which is the Kronecker + delta `\delta(x, y)`). + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I.one() + I[0, 0] + I[1, 1] + I[2, 2] + I[3, 3] + I[4, 4] + I[5, 5] + + I[6, 6] + I[7, 7] + I[8, 8] + I[9, 9] + I[10, 10] + + I[11, 11] + I[12, 12] + I[13, 13] + I[14, 14] + I[15, 15] + """ + return self.sum_of_monomials((x, x) for x in self._poset) + + delta = one + + @cached_method + def zeta(self): + r""" + Return the `\zeta` function in ``self``. + + The `\zeta` function on a poset `P` is given by + + .. MATH:: + + \zeta(x, y) = \begin{cases} + 1 & x \leq y, \\ + 0 & x \not\leq y. + \end{cases} + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I.zeta() * I.mobius() == I.one() + True + """ + return self.sum(self.basis()) + + @cached_method + def mobius(self): + """ + Return the Mobius function of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: I = P.incidence_algebra(QQ) + sage: I.mobius() + I[0, 0] - I[0, 1] - I[0, 2] + I[0, 3] + I[1, 1] + - I[1, 3] + I[2, 2] - I[2, 3] + I[3, 3] + """ + mu = self._poset.mobius_function + R = self.base_ring() + return self.sum_of_terms((A, R(mu(*A))) for A in self.basis().keys()) + + def __getitem__(self, A): + """ + Return the basis element indexed by ``A``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I[2, 6] + I[2, 6] + sage: I[(2, 6)] + I[2, 6] + sage: I[[2, 6]] + I[2, 6] + sage: I[2] + I[2, 2] + + sage: I[2, 5] + Traceback (most recent call last): + ... + ValueError: not an interval + + sage: I[-1] + Traceback (most recent call last): + ... + ValueError: not an element of the poset + """ + if not isinstance(A, (list, tuple)): + if A not in self._poset.list(): + raise ValueError("not an element of the poset") + A = (A, A) + else: + A = tuple(A) + if len(A) != 2 or A not in self.basis().keys(): + raise ValueError("not an interval") + return self.monomial(A) + + @lazy_attribute + def _linear_extension(self): + """ + Return a fixed linear extension of the defining poset of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I._linear_extension + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) + """ + return tuple(self._poset.linear_extension()) + + class Element(CombinatorialFreeModule.Element): + """ + An element of an incidence algebra. + """ + def __call__(self, x, y): + """ + Return ``self(x, y)``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: mu = I.mobius() + sage: mu(0, 12) + 1 + sage: mu(0, 7) + -1 + sage: mu(15, 0) + 0 + """ + P = self.parent()._poset + x = P(x) + y = P(y) + return self[x,y] + + @cached_method + def to_matrix(self): + r""" + Return ``self`` as a matrix. + + We define a matrix `M_{xy} = \alpha(x, y)` for some element + `\alpha \in I_P` in the incidence algebra `I_P` and we order + the elements `x,y \in P` by some linear extension of `P`. This + defines an algebra (iso)morphism; in particular, multiplication + in the incidence algebra goes to matrix multiplication. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: I = P.incidence_algebra(QQ) + sage: I.mobius().to_matrix() + [ 1 -1 -1 1] + [ 0 1 0 -1] + [ 0 0 1 -1] + [ 0 0 0 1] + sage: I.zeta().to_matrix() + [1 1 1 1] + [0 1 0 1] + [0 0 1 1] + [0 0 0 1] + + TESTS: + + We check that this is an algebra (iso)morphism:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: mu = I.mobius() + sage: (mu*mu).to_matrix() == mu.to_matrix() * mu.to_matrix() + True + """ + P = self.parent() + MS = MatrixSpace(P.base_ring(), P._poset.cardinality(), sparse=True) + L = P._linear_extension + M = copy(MS.zero()) + for i,c in self: + M[L.index(i[0]), L.index(i[1])] = c + M.set_immutable() + return M + + def is_unit(self): + """ + Return if ``self`` is a unit. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: I = P.incidence_algebra(QQ) + sage: mu = I.mobius() + sage: mu.is_unit() + True + sage: zeta = I.zeta() + sage: zeta.is_unit() + True + sage: x = mu - I.zeta() + I[2,2] + sage: x.is_unit() + False + sage: y = I.mobius() + I.zeta() + sage: y.is_unit() + True + + This depends on the base ring:: + + sage: I = P.incidence_algebra(ZZ) + sage: y = I.mobius() + I.zeta() + sage: y.is_unit() + False + """ + return all(self[x,x].is_unit() for x in self.parent()._poset) + + def __invert__(self): + """ + Return the inverse of ``self`` if it exists. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: I = P.incidence_algebra(QQ) + sage: mu = I.mobius() + sage: ~mu + I[0, 0] + I[0, 1] + I[0, 2] + I[0, 3] + I[1, 1] + + I[1, 3] + I[2, 2] + I[2, 3] + I[3, 3] + sage: x = mu - I.zeta() + I[2,2] + sage: ~x + Traceback (most recent call last): + ... + ValueError: element is not invertible + + TESTS:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: mu = I.mobius() + sage: ~mu == I.zeta() + True + sage: ~I.one() == I.one() + True + """ + M = self.to_matrix() + if not M.is_invertible(): + raise ValueError("element is not invertible") + inv = ~M + L = self.parent()._linear_extension + return self.parent().sum_of_terms( ((L[i], L[j]), inv[i,j]) + for i,j in inv.nonzero_positions(copy=False) ) + diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index e0a21339b58..3e09d0ab2ba 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -51,6 +51,7 @@ :meth:`~FinitePoset.has_isomorphic_subposet` | Return ``True`` if the poset contains a subposet isomorphic to another poset, and ``False`` otherwise. :meth:`~FinitePoset.has_top` | Returns True if the poset contains a unique maximal element, and False otherwise. :meth:`~FinitePoset.height` | Return the height (number of elements in the longest chain) of the poset. + :meth:`~FinitePoset.incidence_algebra` | Return the indicence algebra of ``self``. :meth:`~FinitePoset.incomparability_graph` | Returns the incomparability graph of the poset. :meth:`~FinitePoset.interval` | Returns a list of the elements `z` such that `x \le z \le y`. :meth:`~FinitePoset.intervals` | Returns a list of all intervals of the poset. @@ -5003,6 +5004,20 @@ def p_partition_enumerator(self, tup, R, check=False): res += QR.Fundamental()(Composition(from_subset=(descents, n))) return res + def incidence_algebra(self, R, prefix='I'): + r""" + Return the incidence algebra of ``self`` over ``R``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: P.incidence_algebra(QQ) + Incidence algebra of Finite lattice containing 16 elements + over Rational Field + """ + from sage.combinat.posets.incidence_algebras import IncidenceAlgebra + return IncidenceAlgebra(R, self, prefix) + FinitePoset._dual_class = FinitePoset ##### Posets ##### From 491feb4ef6d9af1bc05f390d521f94cd5a1dc908 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 30 Dec 2014 11:14:56 +0100 Subject: [PATCH 070/665] Trac 17543: move TorsionPoint to a new file torsion_point.py --- src/sage/modular/abvar/finite_subgroup.py | 257 +------------------ src/sage/modular/abvar/torsion_point.py | 274 +++++++++++++++++++++ src/sage/modular/abvar/torsion_subgroup.py | 3 +- 3 files changed, 277 insertions(+), 257 deletions(-) create mode 100644 src/sage/modular/abvar/torsion_point.py diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 97ae1c7fa3b..9e461001c61 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -93,9 +93,9 @@ # http://www.gnu.org/licenses/ # ########################################################################### +from sage.modular.abvar.torsion_point import TorsionPoint from sage.modules.module import Module_old from sage.modules.free_module import is_FreeModule -from sage.structure.element import ModuleElement from sage.structure.sequence import Sequence from sage.rings.all import gcd, lcm, QQ, ZZ, QQbar, Integer, composite_field from sage.misc.misc import prod @@ -844,258 +844,3 @@ def lattice(self): [ 0 1/5] """ return self.__lattice - -########################################################################### -# Elements of finite order -########################################################################### - -class TorsionPoint(ModuleElement): - def __init__(self, parent, element, check=True): - """ - An element of a finite subgroup of a modular abelian variety. - - INPUT: - - - - ``parent`` - a finite subgroup of a modular abelian - variety - - - ``element`` - a QQ vector space element that - represents this element in terms of the ambient rational homology - - - ``check`` - bool (default: True) whether to check - that element is in the appropriate vector space - - - EXAMPLES: The following calls the TorsionPoint constructor - implicitly:: - - sage: J = J0(11) - sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G - Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 - sage: type(G.0) - - """ - ModuleElement.__init__(self, parent) - if check: - if not element in parent.abelian_variety().vector_space(): - raise TypeError("element must be a vector in the abelian variety's rational homology (embedded in the ambient Jacobian product)") - if element.denominator() == 1: - element = element.parent().zero_vector() - self.__element = element - - def element(self): - """ - Return an underlying QQ-vector space element that defines this - element of a modular abelian variety. This is a vector in the - ambient Jacobian variety's rational homology. - - EXAMPLES: We create some elements of `J_0(11)`:: - - sage: J = J0(11) - sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G - Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 - sage: G.0.element() - (1/3, 0) - - The underlying element is a vector over the rational numbers:: - - sage: v = (G.0-G.1).element(); v - (1/3, -1/5) - sage: type(v) - - """ - return self.__element - - def _repr_(self): - r""" - Return string representation of this finite subgroup element. Since - they are represented as equivalences classes of rational homology - modulo integral homology, we represent an element corresponding to - `v` in the rational homology by ``[v]``. - - EXAMPLES:: - - sage: J = J0(11) - sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G - Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 - sage: G.0._repr_() - '[(1/3, 0)]' - """ - return '[%s]'%self.__element - - def _add_(self, other): - """ - Add two finite subgroup elements with the same parent. This is - called implicitly by +. - - INPUT: - - - - ``other`` - a TorsionPoint with the same parent as - self - - - OUTPUT: a TorsionPoint - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0._add_(G.1) - [(1/3, 1/5)] - sage: G.0 + G.1 - [(1/3, 1/5)] - """ - return TorsionPoint(self.parent(), self.__element + other.__element, check=False) - - def _sub_(self, other): - """ - Subtract two finite subgroup elements with the same parent. This is - called implicitly by +. - - INPUT: - - - - ``other`` - a TorsionPoint with the same parent as - self - - - OUTPUT: a TorsionPoint - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0._sub_(G.1) - [(1/3, -1/5)] - sage: G.0 - G.1 - [(1/3, -1/5)] - """ - return TorsionPoint(self.parent(), self.__element - other.__element, check=False) - - def _neg_(self): - """ - Negate a finite subgroup element. - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0._neg_() - [(-1/3, 0)] - """ - return TorsionPoint(self.parent(), -self.__element, check=False) - - def _rmul_(self, left): - """ - Left multiply a finite subgroup element by an integer. - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0._rmul_(2) - [(2/3, 0)] - sage: 2*G.0 - [(2/3, 0)] - """ - return TorsionPoint(self.parent(), ZZ(left) * self.__element, check=False) - - def _lmul_(self, right): - """ - Right multiply a finite subgroup element by an integer. - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0._lmul_(2) - [(2/3, 0)] - sage: G.0 * 2 - [(2/3, 0)] - """ - return TorsionPoint(self.parent(), self.__element * right, check=False) - - def __cmp__(self, right): - """ - Compare self and right. - - INPUT: - - - - ``self, right`` - elements of the same finite - abelian variety subgroup. - - - OUTPUT: -1, 0, or 1 - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: cmp(G.0, G.1) - 1 - sage: cmp(G.0, G.0) - 0 - sage: 3*G.0 == 0 - True - sage: 3*G.0 == 5*G.1 - True - - We make sure things that shouldn't be equal aren't:: - - sage: H = J0(14).finite_subgroup([[1/3,0]]) - sage: G.0 == H.0 - False - sage: cmp(G.0, H.0) - -1 - sage: G.0 - [(1/3, 0)] - sage: H.0 - [(1/3, 0)] - """ - if not isinstance(right, TorsionPoint): - return cmp(type(self), type(right)) - A = self.parent().abelian_variety() - B = right.parent().abelian_variety() - if A.groups() != B.groups(): - return cmp(A,B) - elif self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice() + B.lattice(): - return 0 - else: - return cmp(self.__element, right.__element) - - def additive_order(self): - """ - Return the additive order of this element. - - EXAMPLES:: - - sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) - sage: G.0.additive_order() - 3 - sage: G.1.additive_order() - 5 - sage: (G.0 + G.1).additive_order() - 15 - sage: (3*G.0).additive_order() - 1 - """ - return self._relative_element().denominator() - - def _relative_element(self): - """ - Return coordinates of this element in terms of basis for the - integral homology of the containing abelian variety. - - OUTPUT: vector - - EXAMPLES:: - - sage: A = J0(43)[1]; A - Simple abelian subvariety 43b(1,43) of dimension 2 of J0(43) - sage: C = A.cuspidal_subgroup(); C - Finite subgroup with invariants [7] over QQ of Simple abelian subvariety 43b(1,43) of dimension 2 of J0(43) - sage: x = C.0; x - [(0, 1/7, 0, 6/7, 0, 5/7)] - sage: x._relative_element() - (0, 1/7, 6/7, 5/7) - """ - # check=False prevents testing that the element is really in - # the lattice, not just in the corresponding QQ-vector space. - return self.parent().abelian_variety().lattice().coordinate_vector(self.__element, check=False) diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py new file mode 100644 index 00000000000..25bf1ec20b5 --- /dev/null +++ b/src/sage/modular/abvar/torsion_point.py @@ -0,0 +1,274 @@ +""" +Torsion points on modular abelian varieties + +AUTHORS: + +- William Stein (2007-03) + +- Peter Bruin (2014-12): move TorsionPoint to a separate file + +""" + +#***************************************************************************** +# Copyright (C) 2007 William Stein +# Copyright (C) 2014 Peter Bruin +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + + +from sage.structure.element import ModuleElement + +class TorsionPoint(ModuleElement): + def __init__(self, parent, element, check=True): + """ + An element of a finite subgroup of a modular abelian variety. + + INPUT: + + + - ``parent`` - a finite subgroup of a modular abelian + variety + + - ``element`` - a QQ vector space element that + represents this element in terms of the ambient rational homology + + - ``check`` - bool (default: True) whether to check + that element is in the appropriate vector space + + + EXAMPLES: The following calls the TorsionPoint constructor + implicitly:: + + sage: J = J0(11) + sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G + Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 + sage: type(G.0) + + """ + ModuleElement.__init__(self, parent) + if check: + if not element in parent.abelian_variety().vector_space(): + raise TypeError("element must be a vector in the abelian variety's rational homology (embedded in the ambient Jacobian product)") + if element.denominator() == 1: + element = element.parent().zero_vector() + self.__element = element + + def element(self): + """ + Return an underlying QQ-vector space element that defines this + element of a modular abelian variety. This is a vector in the + ambient Jacobian variety's rational homology. + + EXAMPLES: We create some elements of `J_0(11)`:: + + sage: J = J0(11) + sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G + Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 + sage: G.0.element() + (1/3, 0) + + The underlying element is a vector over the rational numbers:: + + sage: v = (G.0-G.1).element(); v + (1/3, -1/5) + sage: type(v) + + """ + return self.__element + + def _repr_(self): + r""" + Return string representation of this finite subgroup element. Since + they are represented as equivalences classes of rational homology + modulo integral homology, we represent an element corresponding to + `v` in the rational homology by ``[v]``. + + EXAMPLES:: + + sage: J = J0(11) + sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G + Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 + sage: G.0._repr_() + '[(1/3, 0)]' + """ + return '[%s]'%self.__element + + def _add_(self, other): + """ + Add two finite subgroup elements with the same parent. This is + called implicitly by +. + + INPUT: + + + - ``other`` - a TorsionPoint with the same parent as + self + + + OUTPUT: a TorsionPoint + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0._add_(G.1) + [(1/3, 1/5)] + sage: G.0 + G.1 + [(1/3, 1/5)] + """ + return TorsionPoint(self.parent(), self.__element + other.__element, check=False) + + def _sub_(self, other): + """ + Subtract two finite subgroup elements with the same parent. This is + called implicitly by +. + + INPUT: + + + - ``other`` - a TorsionPoint with the same parent as + self + + + OUTPUT: a TorsionPoint + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0._sub_(G.1) + [(1/3, -1/5)] + sage: G.0 - G.1 + [(1/3, -1/5)] + """ + return TorsionPoint(self.parent(), self.__element - other.__element, check=False) + + def _neg_(self): + """ + Negate a finite subgroup element. + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0._neg_() + [(-1/3, 0)] + """ + return TorsionPoint(self.parent(), -self.__element, check=False) + + def _rmul_(self, left): + """ + Left multiply a finite subgroup element by an integer. + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0._rmul_(2) + [(2/3, 0)] + sage: 2*G.0 + [(2/3, 0)] + """ + return TorsionPoint(self.parent(), ZZ(left) * self.__element, check=False) + + def _lmul_(self, right): + """ + Right multiply a finite subgroup element by an integer. + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0._lmul_(2) + [(2/3, 0)] + sage: G.0 * 2 + [(2/3, 0)] + """ + return TorsionPoint(self.parent(), self.__element * right, check=False) + + def __cmp__(self, right): + """ + Compare self and right. + + INPUT: + + + - ``self, right`` - elements of the same finite + abelian variety subgroup. + + + OUTPUT: -1, 0, or 1 + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: cmp(G.0, G.1) + 1 + sage: cmp(G.0, G.0) + 0 + sage: 3*G.0 == 0 + True + sage: 3*G.0 == 5*G.1 + True + + We make sure things that shouldn't be equal aren't:: + + sage: H = J0(14).finite_subgroup([[1/3,0]]) + sage: G.0 == H.0 + False + sage: cmp(G.0, H.0) + -1 + sage: G.0 + [(1/3, 0)] + sage: H.0 + [(1/3, 0)] + """ + if not isinstance(right, TorsionPoint): + return cmp(type(self), type(right)) + A = self.parent().abelian_variety() + B = right.parent().abelian_variety() + if A.groups() != B.groups(): + return cmp(A,B) + elif self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice() + B.lattice(): + return 0 + else: + return cmp(self.__element, right.__element) + + def additive_order(self): + """ + Return the additive order of this element. + + EXAMPLES:: + + sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) + sage: G.0.additive_order() + 3 + sage: G.1.additive_order() + 5 + sage: (G.0 + G.1).additive_order() + 15 + sage: (3*G.0).additive_order() + 1 + """ + return self._relative_element().denominator() + + def _relative_element(self): + """ + Return coordinates of this element in terms of basis for the + integral homology of the containing abelian variety. + + OUTPUT: vector + + EXAMPLES:: + + sage: A = J0(43)[1]; A + Simple abelian subvariety 43b(1,43) of dimension 2 of J0(43) + sage: C = A.cuspidal_subgroup(); C + Finite subgroup with invariants [7] over QQ of Simple abelian subvariety 43b(1,43) of dimension 2 of J0(43) + sage: x = C.0; x + [(0, 1/7, 0, 6/7, 0, 5/7)] + sage: x._relative_element() + (0, 1/7, 6/7, 5/7) + """ + # check=False prevents testing that the element is really in + # the lattice, not just in the corresponding QQ-vector space. + return self.parent().abelian_variety().lattice().coordinate_vector(self.__element, check=False) diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index d75e83f850e..a50d3ac8069 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -84,8 +84,9 @@ # http://www.gnu.org/licenses/ # ########################################################################### +from sage.modular.abvar.torsion_point import TorsionPoint from sage.modules.module import Module -from finite_subgroup import FiniteSubgroup, TorsionPoint +from finite_subgroup import FiniteSubgroup from sage.rings.all import divisors, gcd, ZZ, prime_range from sage.sets.primes import Primes from sage.modular.arithgroup.all import is_Gamma0 From 7909f71f023fb2a1228d5ef3c4be005e765e8721 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 30 Dec 2014 11:16:29 +0100 Subject: [PATCH 071/665] Trac 17543: make all module classes inherit from Module --- src/sage/modular/abvar/finite_subgroup.py | 64 +++++++++++++++------- src/sage/modular/abvar/torsion_point.py | 23 +++++--- src/sage/modular/abvar/torsion_subgroup.py | 10 ++-- src/sage/modular/overconvergent/genus0.py | 24 ++++---- src/sage/modules/module.pxd | 4 +- src/sage/schemes/toric/divisor.py | 12 ++-- src/sage/structure/formal_sum.py | 22 ++------ src/sage/structure/parent_gens.pyx | 2 - 8 files changed, 86 insertions(+), 75 deletions(-) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 9e461001c61..a5ae7bf8867 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -94,17 +94,20 @@ ########################################################################### from sage.modular.abvar.torsion_point import TorsionPoint -from sage.modules.module import Module_old +from sage.modules.module import Module from sage.modules.free_module import is_FreeModule +from sage.structure.gens_py import abelian_iterator from sage.structure.sequence import Sequence from sage.rings.all import gcd, lcm, QQ, ZZ, QQbar, Integer, composite_field from sage.misc.misc import prod import abvar as abelian_variety -from sage.categories.fields import Fields -_Fields = Fields() -class FiniteSubgroup(Module_old): + +class FiniteSubgroup(Module): + + Element = TorsionPoint + def __init__(self, abvar, field_of_definition=QQ): """ A finite subgroup of a modular abelian variety. @@ -127,16 +130,22 @@ def __init__(self, abvar, field_of_definition=QQ): sage: G = A.torsion_subgroup(3); G Finite subgroup with invariants [3, 3, 3, 3] over QQ of Abelian variety J0(37) of dimension 2 sage: type(G) - + sage: from sage.modular.abvar.finite_subgroup import FiniteSubgroup sage: isinstance(G, FiniteSubgroup) True """ - if field_of_definition not in _Fields: + from sage.categories.category import Category + from sage.categories.fields import Fields + from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + from sage.categories.modules import Modules + + if field_of_definition not in Fields(): raise TypeError("field_of_definition must be a field") if not abelian_variety.is_ModularAbelianVariety(abvar): raise TypeError("abvar must be a modular abelian variety") - Module_old.__init__(self, ZZ) + category = Category.join((Modules(ZZ), FiniteEnumeratedSets())) + Module.__init__(self, ZZ, category=category) self.__abvar = abvar self.__field_of_definition = field_of_definition @@ -554,7 +563,7 @@ def gens(self): except AttributeError: pass - B = [TorsionPoint(self, v) for v in self.lattice().basis() if v.denominator() > 1] + B = [self.element_class(self, v) for v in self.lattice().basis() if v.denominator() > 1] self.__gens = Sequence(B, immutable=True) return self.__gens @@ -584,7 +593,7 @@ def gen(self, n): """ return self.gens()[n] - def __call__(self, x): + def _element_constructor_(self, x, check=True): r""" Coerce `x` into this finite subgroup. @@ -637,20 +646,18 @@ def __call__(self, x): ... TypeError: x does not define an element of self """ + if isinstance(x, self.element_class) and x.parent() is self: + return x if isinstance(x, TorsionPoint): - if x.parent() is self: - return x - elif x.parent() == self: - return TorsionPoint(self, x.element(), check=False) + if x.parent() == self: + return self.element_class(self, x.element(), check=False) elif x.parent().abelian_variety() == self.abelian_variety(): - return self(x.element()) - else: - raise TypeError("x does not define an element of self") + return self(x.element(), check=check) else: - z = self.abelian_variety().vector_space()(x) - if not z in self.lattice(): - raise TypeError("x does not define an element of self") - return TorsionPoint(self, z, check=False) + z = self.abelian_variety().vector_space()(x, check=check) + if z in self.lattice(): + return self.element_class(self, z, check=False) + raise TypeError("x does not define an element of self") def __contains__(self, x): @@ -789,6 +796,23 @@ def invariants(self): self.__invariants = I return I + def generator_orders(self): + """ + Return the orders of the chosen generators of ``self``. + + EXAMPLES:: + + sage: G = J0(24).cuspidal_subgroup() + sage: G.gens() + [[(1/4, 0)], [(0, 1/2)]] + sage: G.generator_orders() + [4, 2] + """ + return [x.additive_order() for x in self.gens()] + + __iter__ = abelian_iterator + + class FiniteSubgroup_lattice(FiniteSubgroup): def __init__(self, abvar, lattice, field_of_definition=QQbar, check=True): """ diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index 25bf1ec20b5..56781a831c9 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -47,7 +47,7 @@ def __init__(self, parent, element, check=True): sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 sage: type(G.0) - + """ ModuleElement.__init__(self, parent) if check: @@ -119,7 +119,8 @@ def _add_(self, other): sage: G.0 + G.1 [(1/3, 1/5)] """ - return TorsionPoint(self.parent(), self.__element + other.__element, check=False) + P = self.parent() + return P.element_class(P, self.__element + other.__element, check=False) def _sub_(self, other): """ @@ -143,7 +144,8 @@ def _sub_(self, other): sage: G.0 - G.1 [(1/3, -1/5)] """ - return TorsionPoint(self.parent(), self.__element - other.__element, check=False) + P = self.parent() + return P.element_class(P, self.__element - other.__element, check=False) def _neg_(self): """ @@ -155,7 +157,8 @@ def _neg_(self): sage: G.0._neg_() [(-1/3, 0)] """ - return TorsionPoint(self.parent(), -self.__element, check=False) + P = self.parent() + return P.element_class(P, -self.__element, check=False) def _rmul_(self, left): """ @@ -169,7 +172,8 @@ def _rmul_(self, left): sage: 2*G.0 [(2/3, 0)] """ - return TorsionPoint(self.parent(), ZZ(left) * self.__element, check=False) + P = self.parent() + return P.element_class(P, left * self.__element, check=False) def _lmul_(self, right): """ @@ -183,7 +187,8 @@ def _lmul_(self, right): sage: G.0 * 2 [(2/3, 0)] """ - return TorsionPoint(self.parent(), self.__element * right, check=False) + P = self.parent() + return P.element_class(P, self.__element * right, check=False) def __cmp__(self, right): """ @@ -228,10 +233,10 @@ def __cmp__(self, right): B = right.parent().abelian_variety() if A.groups() != B.groups(): return cmp(A,B) - elif self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice() + B.lattice(): + from sage.rings.all import QQ + if self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice() + B.lattice(): return 0 - else: - return cmp(self.__element, right.__element) + return cmp(self.__element, right.__element) def additive_order(self): """ diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index a50d3ac8069..bd4c95ec901 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -110,7 +110,7 @@ def __init__(self, abvar): sage: T = J0(14).rational_torsion_subgroup(); T Torsion subgroup of Abelian variety J0(14) of dimension 1 sage: type(T) - + """ FiniteSubgroup.__init__(self, abvar) @@ -410,8 +410,10 @@ def multiple_of_order(self, maxp=None): return bnd - class QQbarTorsionSubgroup(Module): + + Element = TorsionPoint + def __init__(self, abvar): """ Group of all torsion points over the algebraic closure on an @@ -460,7 +462,7 @@ def field_of_definition(self): """ return self.__abvar.base_field() - def __call__(self, x): + def _element_constructor_(self, x): r""" Create an element in this finite group. @@ -480,7 +482,7 @@ def __call__(self, x): 4 """ v = self.__abvar.vector_space()(x) - return TorsionPoint(self, v) + return self.element_class(self, v) def abelian_variety(self): """ diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index f9ac34c759d..902bc534a87 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -182,7 +182,7 @@ from sage.modular.arithgroup.all import (Gamma1, is_Gamma0, is_Gamma1) from sage.modular.modform.element import ModularFormElement from sage.modules.all import vector -from sage.modules.module import Module_old +from sage.modules.module import Module from sage.structure.element import Vector, ModuleElement from sage.plot.plot import plot from sage.rings.all import (O, Infinity, ZZ, QQ, pAdicField, PolynomialRing, PowerSeriesRing, is_pAdicField) @@ -259,7 +259,7 @@ def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec = 20, c # Main class definition # ######################### -class OverconvergentModularFormsSpace(Module_old): +class OverconvergentModularFormsSpace(Module): r""" A space of overconvergent modular forms of level `\Gamma_0(p)`, where `p` is a prime such that `X_0(p)` has genus 0. @@ -310,7 +310,7 @@ def __init__(self, prime, weight, radius, base_ring, prec, char): if not self._wtchar.is_even(): raise ValueError("Weight-character must be even") - Module_old.__init__(self, base_ring) + Module.__init__(self, base_ring) self._prec = prec @@ -426,7 +426,7 @@ def base_extend(self, ring): else: raise TypeError("Base extension of self (over '%s') to ring '%s' not defined." % (self.base_ring(), ring)) - def _an_element_impl(self): + def _an_element_(self): r""" Return an element of this space (used by the coercion machinery). @@ -471,7 +471,6 @@ def weight(self): """ return self._wtchar - def normalising_factor(self): r""" The normalising factor `c` such that `g = c f` is a parameter for the @@ -574,7 +573,6 @@ def prime(self): """ return self._p - def radius(self): r""" The radius of overconvergence of this space. @@ -621,11 +619,9 @@ def prec(self): ##################################### # Element construction and coercion # - # (unfortunately not using # - # the new coercion model) # ##################################### - def __call__(self, input): + def _element_constructor_(self, input): r""" Create an element of this space. Allowable inputs are: @@ -757,7 +753,7 @@ def _coerce_from_ocmf(self, f): raise TypeError("Cannot create an element of '%s' from element of incompatible space '%s'" % (self, input.parent())) return self(self._qsr(f.q_expansion())) - def _coerce_impl(self, x): + def _coerce_map_from_(self, other): r""" Canonical coercion of x into self. Here the possibilities for x are more restricted. @@ -775,11 +771,11 @@ def _coerce_impl(self, x): sage: M.coerce(1) 3-adic overconvergent modular form of weight-character 0 with q-expansion 1 + O(q^20) """ - if isinstance(x, OverconvergentModularFormElement) and self.base_ring().has_coerce_map_from(x.base_ring()): - return self._coerce_from_ocmf(x) + if (isinstance(other, OverconvergentModularFormsSpace) and + self.base_ring().has_coerce_map_from(other.base_ring())): + return True else: - return self.base_ring().coerce(x) * self.gen(0) - + return self.base_ring().has_coerce_map_from(other) def coordinate_vector(self, x): r""" diff --git a/src/sage/modules/module.pxd b/src/sage/modules/module.pxd index 2bfb727dd52..032cce6d69e 100644 --- a/src/sage/modules/module.pxd +++ b/src/sage/modules/module.pxd @@ -1,4 +1,4 @@ -cimport sage.structure.parent_gens +from sage.structure.parent cimport Parent -cdef class Module_old(sage.structure.parent_gens.ParentWithAdditiveAbelianGens): +cdef class Module(Parent): pass diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 23ca235719b..b824bb5d736 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -173,7 +173,7 @@ from sage.geometry.toric_lattice_element import is_ToricLatticeElement from sage.homology.simplicial_complex import SimplicialComplex from sage.matrix.constructor import matrix -from sage.misc.all import latex, flatten, prod +from sage.misc.all import cached_method, flatten, latex, prod from sage.modules.all import vector from sage.modules.free_module import (FreeModule_ambient_field, FreeModule_ambient_pid) @@ -297,6 +297,7 @@ def ngens(self): """ return self.scheme().fan().nrays() + @cached_method def gens(self): r""" Return the generators of the divisor group. @@ -308,12 +309,9 @@ def gens(self): sage: TDiv.gens() (V(x), V(y), V(z)) """ - # Note: self._gens is originally incorrectly set by the parent class - if self._gens is None: - one = self.base_ring().one() - self._gens = tuple(ToricDivisor_generic([(one, c)], self) - for c in self.scheme().gens()) - return self._gens + one = self.base_ring().one() + return tuple(ToricDivisor_generic([(one, c)], self) + for c in self.scheme().gens()) def gen(self,i): r""" diff --git a/src/sage/structure/formal_sum.py b/src/sage/structure/formal_sum.py index f2c79bb57e0..f8c1bd634e2 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -68,11 +68,10 @@ import operator import sage.misc.latex -from sage.modules.module import Module_old as Module +from sage.modules.module import Module from sage.structure.element import ModuleElement from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent -from sage.structure.parent_base import ParentWithBase from sage.structure.coerce import LeftModuleAction, RightModuleAction from sage.categories.action import PrecomposedAction from sage.structure.unique_representation import UniqueRepresentation @@ -86,6 +85,10 @@ class FormalSums(UniqueRepresentation, Module): sage: FormalSums() Abelian Group of all Formal Finite Sums over Integer Ring + sage: FormalSums(ZZ) + Abelian Group of all Formal Finite Sums over Integer Ring + sage: FormalSums(GF(7)) + Abelian Group of all Formal Finite Sums over Finite Field of size 7 sage: FormalSums(ZZ[sqrt(2)]) Abelian Group of all Formal Finite Sums over Order in Number Field in sqrt2 with defining polynomial x^2 - 2 sage: FormalSums(GF(9,'a')) @@ -104,21 +107,6 @@ def __classcall__(cls, base_ring = ZZ): """ return UniqueRepresentation.__classcall__(cls, base_ring) - def __init__(self, base_ring): - """ - INPUT: - - - ``R`` -- a ring (default: ZZ). - - EXAMPLES:: - - sage: FormalSums(ZZ) - Abelian Group of all Formal Finite Sums over Integer Ring - sage: FormalSums(GF(7)) - Abelian Group of all Formal Finite Sums over Finite Field of size 7 - """ - ParentWithBase.__init__(self, base_ring) - def _repr_(self): """ EXAMPLES:: diff --git a/src/sage/structure/parent_gens.pyx b/src/sage/structure/parent_gens.pyx index e5711680d52..e3e0629cc4c 100644 --- a/src/sage/structure/parent_gens.pyx +++ b/src/sage/structure/parent_gens.pyx @@ -107,8 +107,6 @@ def is_ParentWithAdditiveAbelianGens(x): sage: from sage.structure.parent_gens import is_ParentWithAdditiveAbelianGens sage: is_ParentWithAdditiveAbelianGens(QQ) False - sage: is_ParentWithAdditiveAbelianGens(OverconvergentModularForms(3, 0, 1/2)) - True """ return PY_TYPE_CHECK(x, ParentWithAdditiveAbelianGens) From 6fb3692d35cbdba775c77a47e0f546fe61c1421e Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 30 Dec 2014 11:49:57 +0100 Subject: [PATCH 072/665] Trac 17543: documentation improvements --- src/sage/modular/abvar/abvar.py | 8 +-- src/sage/modular/abvar/finite_subgroup.py | 84 ++++++++++------------ src/sage/modular/abvar/morphism.py | 12 ++-- src/sage/modular/abvar/torsion_point.py | 77 +++++++++----------- src/sage/modular/abvar/torsion_subgroup.py | 6 +- 5 files changed, 81 insertions(+), 106 deletions(-) diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index b8bd4cc1165..2b459344709 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -3655,11 +3655,11 @@ def groups(self): def lattice(self): r""" - Return the lattice the defines this modular symbols modular abelian - variety. + Return the lattice defining this modular abelian variety. + + OUTPUT: - OUTPUT: a free `\ZZ`-module embedded in an ambient - `\QQ`-vector space + A free `\ZZ`-module embedded in an ambient `\QQ`-vector space. EXAMPLES:: diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index a5ae7bf8867..7131b3a7ca0 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -114,17 +114,15 @@ def __init__(self, abvar, field_of_definition=QQ): INPUT: + - ``abvar`` -- a modular abelian variety - - ``abvar`` - a modular abelian variety - - - ``field_of_definition`` - a field over which this - group is defined. - + - ``field_of_definition`` -- a field over which this group is + defined - EXAMPLES: This is an abstract base class, so there are no instances - of this class itself. + EXAMPLES: - :: + This is an abstract base class, so there are no instances of + this class itself:: sage: A = J0(37) sage: G = A.torsion_subgroup(3); G @@ -197,17 +195,19 @@ def _relative_basis_matrix(self): # General functionality def __cmp__(self, other): """ - Compare this finite subgroup to other. + Compare ``self`` to ``other``. + + If ``other`` is not a :class:`FiniteSubgroup`, then the types + of ``self`` and ``other`` are compared. If ``other`` is a + :class:`FiniteSubgroup` and the ambient abelian varieties are + not equal, then the ambient abelian varieties are compared. + If ``other`` is a :class:`FiniteSubgroup` and the ambient + abelian varieties are equal, then the subgroups are compared + via their corresponding lattices. - If other is not a modular abelian variety finite subgroup, then the - types of self and other are compared. If other is a finite - subgroup, and the ambient abelian varieties are equal, then the - subgroups themselves are compared, by comparing their full modules. - If the containing abelian varieties are not equal and their ambient - varieties are different they are compared; if they are the same, - then a NotImplemnetedError is raised (this is temporary). + EXAMPLES: - EXAMPLES: We first compare to subgroups of `J_0(37)`:: + We first compare two subgroups of `J_0(37)`:: sage: A = J0(37) sage: G = A.torsion_subgroup(3); G.order() @@ -595,11 +595,11 @@ def gen(self, n): def _element_constructor_(self, x, check=True): r""" - Coerce `x` into this finite subgroup. + Convert `x` into this finite subgroup. - This works when the abelian varieties that contains x and self are - the same, or if `x` is coercible into the rational homology - (viewed as an abstract `\QQ`-vector space). + This works when the abelian varieties that contain `x` and + ``self`` are the same, or if `x` is convertible into the + rational homology (viewed as an abstract `\QQ`-vector space). EXAMPLES: We first construct the `11`-torsion subgroup of `J_0(23)`:: @@ -609,20 +609,16 @@ def _element_constructor_(self, x, check=True): sage: G.invariants() [11, 11, 11, 11] - We also construct the cuspidal subgroup. - - :: + We also construct the cuspidal subgroup:: sage: C = J.cuspidal_subgroup() sage: C.invariants() [11] - Coercing something into its parent returns it:: - sage: G(G.0) is G.0 True - We coerce an element from the cuspidal subgroup into the + We convert an element from the cuspidal subgroup into the `11`-torsion subgroup:: sage: z = G(C.0); z @@ -630,15 +626,14 @@ def _element_constructor_(self, x, check=True): sage: z.parent() == G True - We coerce a list, which defines an element of the underlying - ``full_module`` into `G`, and verify an - equality:: + We convert a list, which defines an element of the underlying + ``full_module`` into `G`, and verify an equality:: sage: x = G([1/11, 1/11, 0, -1/11]) sage: x == G([1/11, 1/11, 0, 10/11]) True - Finally we attempt to coerce in an element that shouldn't work, + Finally we attempt to convert an element that shouldn't work, since is is not in `G`:: sage: G(J.torsion_subgroup(3).0) @@ -662,10 +657,11 @@ def _element_constructor_(self, x, check=True): def __contains__(self, x): """ - Returns True if x is contained in this finite subgroup. + Returns True if `x` is contained in this finite subgroup. + + EXAMPLES: - EXAMPLES: We define two distinct finite subgroups of - `J_0(27)`:: + We define two distinct finite subgroups of `J_0(27)`:: sage: G1 = J0(27).rational_cusp_subgroup(); G1 Finite subgroup with invariants [3] over QQ of Abelian variety J0(27) of dimension 1 @@ -676,8 +672,7 @@ def __contains__(self, x): sage: G2.gens() [[(1/3, 0)], [(0, 1/3)]] - Now we check whether various elements are in `G_1` and - `G_2`:: + Now we check whether various elements are in `G_1` and `G_2`:: sage: G2.0 in G1 True @@ -688,7 +683,7 @@ def __contains__(self, x): sage: G1.0 in G2 True - The integer `0` is in, since it coerces in:: + The integer `0` is in `G_1`:: sage: 0 in G1 True @@ -709,8 +704,8 @@ def __contains__(self, x): def subgroup(self, gens): """ - Return the subgroup of self spanned by the given generators, which - all must be elements of self. + Return the subgroup of ``self`` spanned by the given + generators, which must all be elements of ``self``. EXAMPLES:: @@ -718,19 +713,16 @@ def subgroup(self, gens): sage: G = J.torsion_subgroup(11); G Finite subgroup with invariants [11, 11, 11, 11] over QQ of Abelian variety J0(23) of dimension 2 - We create the subgroup of the 11-torsion subgroup of - `J_0(23)` generated by the first `11`-torsion - point:: + We create the subgroup of the 11-torsion subgroup of `J_0(23)` + generated by the first `11`-torsion point:: sage: H = G.subgroup([G.0]); H Finite subgroup with invariants [11] over QQbar of Abelian variety J0(23) of dimension 2 sage: H.invariants() [11] - We can also create a subgroup from a list of objects that coerce - into the ambient rational homology. - - :: + We can also create a subgroup from a list of objects that can + be converted into the ambient rational homology:: sage: H == G.subgroup([[1/11,0,0,0]]) True diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index a360fbf7370..a68f6bb3621 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -509,22 +509,20 @@ def _image_of_element(self, x): def _image_of_finite_subgroup(self, G): """ - Return the image of the finite group `G` under this - morphism. + Return the image of the finite group `G` under ``self``. INPUT: + - ``G`` -- a finite subgroup of the domain of ``self`` - - ``G`` - a finite subgroup of the domain of this - morphism - + OUTPUT: - OUTPUT: a finite subgroup of the codomain + A finite subgroup of the codomain. EXAMPLES:: sage: J = J0(33); A = J[0]; B = J[1] - sage: C = A.intersection(B)[0] ; C + sage: C = A.intersection(B)[0]; C Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: t = J.hecke_operator(3) sage: D = t(C); D diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index 56781a831c9..d109bf7b930 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -24,24 +24,22 @@ class TorsionPoint(ModuleElement): def __init__(self, parent, element, check=True): - """ + r""" An element of a finite subgroup of a modular abelian variety. INPUT: + - ``parent`` -- a finite subgroup of a modular abelian variety - - ``parent`` - a finite subgroup of a modular abelian - variety - - - ``element`` - a QQ vector space element that - represents this element in terms of the ambient rational homology + - ``element`` -- a `\QQ`-vector space element that represents + this element in terms of the ambient rational homology - - ``check`` - bool (default: True) whether to check - that element is in the appropriate vector space + - ``check`` -- bool (default: True): whether to check that + element is in the appropriate vector space + EXAMPLES: - EXAMPLES: The following calls the TorsionPoint constructor - implicitly:: + The following calls the TorsionPoint constructor implicitly:: sage: J = J0(11) sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G @@ -58,12 +56,17 @@ def __init__(self, parent, element, check=True): self.__element = element def element(self): - """ - Return an underlying QQ-vector space element that defines this - element of a modular abelian variety. This is a vector in the - ambient Jacobian variety's rational homology. + r""" + Return a vector over `\QQ` defining ``self``. + + OUTPUT: - EXAMPLES: We create some elements of `J_0(11)`:: + - A vector in the rational homology of the ambient modular + Jacobian variety. + + EXAMPLES: + + We create some elements of `J_0(11)`:: sage: J = J0(11) sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G @@ -82,10 +85,14 @@ def element(self): def _repr_(self): r""" - Return string representation of this finite subgroup element. Since - they are represented as equivalences classes of rational homology - modulo integral homology, we represent an element corresponding to - `v` in the rational homology by ``[v]``. + Return a string representation of ``self``. + + .. note:: + + Since they are represented as equivalences classes of + rational homology modulo integral homology, we represent + an element corresponding to `v` in the rational homology + by ``[v]``. EXAMPLES:: @@ -102,15 +109,6 @@ def _add_(self, other): Add two finite subgroup elements with the same parent. This is called implicitly by +. - INPUT: - - - - ``other`` - a TorsionPoint with the same parent as - self - - - OUTPUT: a TorsionPoint - EXAMPLES:: sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) @@ -127,15 +125,6 @@ def _sub_(self, other): Subtract two finite subgroup elements with the same parent. This is called implicitly by +. - INPUT: - - - - ``other`` - a TorsionPoint with the same parent as - self - - - OUTPUT: a TorsionPoint - EXAMPLES:: sage: J = J0(11); G = J.finite_subgroup([[1/3,0], [0,1/5]]) @@ -192,14 +181,12 @@ def _lmul_(self, right): def __cmp__(self, right): """ - Compare self and right. + Compare ``self`` and ``right``. INPUT: - - - ``self, right`` - elements of the same finite - abelian variety subgroup. - + - ``self, right`` -- elements of the same finite abelian + variety subgroup. OUTPUT: -1, 0, or 1 @@ -240,7 +227,7 @@ def __cmp__(self, right): def additive_order(self): """ - Return the additive order of this element. + Return the additive order of ``self``. EXAMPLES:: @@ -258,8 +245,8 @@ def additive_order(self): def _relative_element(self): """ - Return coordinates of this element in terms of basis for the - integral homology of the containing abelian variety. + Return coordinates of ``self`` on a basis for the integral + homology of the containing abelian variety. OUTPUT: vector diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index bd4c95ec901..0461f4edae9 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -464,13 +464,11 @@ def field_of_definition(self): def _element_constructor_(self, x): r""" - Create an element in this finite group. + Create an element in this torsion subgroup. INPUT: - - - ``x`` - vector in `\QQ^{2d}` - + - ``x`` -- vector in `\QQ^{2d}` OUTPUT: torsion point From d6b5edb6436c920b87afd814878e0ecc8933eb2b Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 30 Dec 2014 12:26:36 +0100 Subject: [PATCH 073/665] Trac 17543: deprecate Module_old --- src/sage/modules/module.pyx | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/sage/modules/module.pyx b/src/sage/modules/module.pyx index b4d1f13d31d..a4655278e7f 100644 --- a/src/sage/modules/module.pyx +++ b/src/sage/modules/module.pyx @@ -74,21 +74,19 @@ cdef class Module_old(sage.structure.parent_gens.ParentWithAdditiveAbelianGens): """ Generic module class. """ - - def endomorphism_ring(self): + def __init__(self, *args, **kwds): """ - Return the endomorphism ring of this module in its category. + TESTS:: + + sage: sage.modules.module.Module_old(ZZ) + doctest:...: DeprecationWarning: the class Module_old is superseded by Module. + See http://trac.sagemath.org/17543 for details. + """ - try: - return self.__endomorphism_ring - except AttributeError: - import sage.categories.all - E = sage.categories.all.End(self) - # the following is invalid code, you can't add attributes - # to Cython classes like this. I guess nobody calls this - # method. - self.__endomorphism_ring = E - return E + from sage.misc.superseded import deprecation + deprecation(17543, "the class Module_old is superseded by Module.") + ParentWithAdditiveAbelianGens.__init__(self, *args, **kwds) + cdef class Module(sage.structure.parent.Parent): """ From 2f08773927a86d5511445ff5471dfec3c042c181 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Dec 2014 14:42:45 -0800 Subject: [PATCH 074/665] Added reduced subalgebra and more documentation. --- .../combinat/posets/incidence_algebras.py | 431 ++++++++++++++++++ 1 file changed, 431 insertions(+) diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index 248b288a530..e476f98deaa 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -28,6 +28,32 @@ class IncidenceAlgebra(CombinatorialFreeModule): r""" The incidence algebra of a poset. + + Let `P` be a poset and `R` be a commutative unital associative ring. + The *incidence algebra* `I_P` is the algebra of functions + `\alpha \colon P \times P \to R` such that `\alpha(x, y) = 0` + if `x \not\leq y` where multiplication is given by covolution: + + .. MATH:: + + (\alpha \ast \beta)(x, y) = \sum_{x \leq k \leq y} + \alpha(x, k) \beta(k, y). + + This has a natural basis given by indicator functions for the + interval `[a, b]`, i.e. `X_{a,b}(x,y) = \delta_{ax} \delta_{by}`. + The incidence algebra is a unital algebra with the identity given + by the Kronecker delta `\delta(x, y) = \delta_{xy}`. The Mobius + function of `P` is another element of `I_p` whose inverse is the + `\zeta` function of the poset (so `\zeta(x, y) = 1` for + every interval `[x, y]`). + + .. TODO:: + + Implement the incidence coalgebra. + + REFERENCES: + + - :wikipedia:`Incidence_algebra` """ def __init__(self, R, P, prefix='I'): """ @@ -72,6 +98,43 @@ def _repr_(self): """ return "Incidence algebra of {} over {}".format(self._poset, self.base_ring()) + def _coerce_map_from_(self, R): + """ + Return the coerce map from ``R`` into ``self`` if it exists + or ``False`` otherwise. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: R = I.reduced_subalgebra() + sage: I.has_coerce_map_from(R) + True + sage: I.has_coerce_map_from(QQ) + True + sage: Pp = posets.BooleanLattice(3) + sage: Rp = Pp.incidence_algebra(QQ).reduced_subalgebra() + sage: I.has_coerce_map_from(Rp) + False + """ + if isinstance(R, ReducedIncidenceAlgebra) and R._ambient is self: + return copy(R.lift) + return super(IncidenceAlgebra, self)._coerce_map_from_(R) + + def reduced_subalgebra(self, prefix='R'): + """ + Return the reduced incidence subalgebra. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: I.reduced_subalgebra() + Reduced incidence algebra of Finite lattice containing 16 elements + over Rational Field + """ + return ReducedIncidenceAlgebra(self, prefix) + def poset(self): """ Return the defining poset of ``self``. @@ -87,6 +150,21 @@ def poset(self): """ return self._poset + def some_elements(self): + """ + Return a list of elements of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(1) + sage: I = P.incidence_algebra(QQ) + sage: I.some_elements() + [2*I[0, 0] + 2*I[0, 1] + 3*I[1, 1], + I[0, 0] - I[0, 1] + I[1, 1], + I[0, 0] + I[0, 1] + I[1, 1]] + """ + return [self.an_element(), self.mobius(), self.zeta()] + def product_on_basis(self, A, B): r""" Return the product of basis elements indexed by ``A`` and ``B``. @@ -350,3 +428,356 @@ def __invert__(self): return self.parent().sum_of_terms( ((L[i], L[j]), inv[i,j]) for i,j in inv.nonzero_positions(copy=False) ) +class ReducedIncidenceAlgebra(CombinatorialFreeModule): + r""" + The reduced incidence algebra of a poset. + + The reduced incidence algebra `R_P` is a subalgebra of the + incidence algebra `I_P` where `\alpha(x, y) = \alpha(x', y')` when + `[x, y]` is isomorphic to `[x', y']` as posets. Thus the delta, Mobius, + and zeta functions are all elements of `R_P`. + """ + def __init__(self, I, prefix='R'): + """ + Initialize ``self``. + + TESTS:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: TestSuite(R).run() + """ + self._ambient = I + EC = {} + P = self._ambient._poset + if not P.is_finite(): + raise NotImplementedError("only implemented for finite posets") + for i in self._ambient.basis().keys(): + S = P.subposet(P.interval(*i)) + added = False + for k in EC: + if S._hasse_diagram.is_isomorphic(k._hasse_diagram): + EC[k].append(i) + added = True + break + if not added: + EC[S] = [i] + self._equiv_classes = map(sorted, EC.values()) + self._equiv_classes = {cls[0]: cls for cls in self._equiv_classes} + cat = Algebras(I.base_ring()).FiniteDimensional().WithBasis() + CombinatorialFreeModule.__init__(self, I.base_ring(), + sorted(self._equiv_classes.keys()), + prefix=prefix, category=cat) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: P.incidence_algebra(QQ).reduced_subalgebra() + Reduced incidence algebra of Finite lattice containing 16 elements + over Rational Field + """ + return "Reduced incidence algebra of {} over {}".format( + self._ambient._poset, self.base_ring()) + + def poset(self): + """ + Return the defining poset of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.poset() + Finite lattice containing 16 elements + sage: R.poset() == P + True + """ + return self._ambient._poset + + def some_elements(self): + """ + Return a list of elements of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.some_elements() + [2*R[(0, 0)] + 2*R[(0, 1)] + 3*R[(0, 3)], + R[(0, 0)] - R[(0, 1)] + R[(0, 3)] - R[(0, 7)] + R[(0, 15)], + R[(0, 0)] + R[(0, 1)] + R[(0, 3)] + R[(0, 7)] + R[(0, 15)]] + """ + return [self.an_element(), self.mobius(), self.zeta()] + + @cached_method + def one_basis(self): + """ + Return the index of the element `1` in ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.one_basis() + (0, 0) + """ + for A in self.basis().keys(): + if A[0] == A[1]: + return A + + def delta(self): + """ + Return the Kronecker delta function in ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.delta() + R[(0, 0)] + """ + return self.one() + + @cached_method + def zeta(self): + r""" + Return the `\zeta` function in ``self``. + + The `\zeta` function on a poset `P` is given by + + .. MATH:: + + \zeta(x, y) = \begin{cases} + 1 & x \leq y, \\ + 0 & x \not\leq y. + \end{cases} + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.zeta() + R[(0, 0)] + R[(0, 1)] + R[(0, 3)] + R[(0, 7)] + R[(0, 15)] + """ + return self.sum(self.basis()) + + @cached_method + def mobius(self): + """ + Return the Mobius function of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.mobius() + R[(0, 0)] - R[(0, 1)] + R[(0, 3)] - R[(0, 7)] + R[(0, 15)] + """ + mu = self._ambient._poset.mobius_function + R = self.base_ring() + return self.sum_of_terms((A, R(mu(*A))) for A in self.basis().keys()) + + @cached_method + def _lift_basis(self, x): + """ + Lift the basis element indexed by ``x`` to the ambient incidence + algebra of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R._lift_basis((0, 7)) + I[0, 7] + I[0, 11] + I[0, 13] + I[0, 14] + I[1, 15] + + I[2, 15] + I[4, 15] + I[8, 15] + """ + return self._ambient.sum_of_monomials(self._equiv_classes[x]) + + @lazy_attribute + def lift(self): + """ + Return the lift morphism from ``self`` to the ambient space. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R.lift + Generic morphism: + From: Reduced incidence algebra of Finite lattice containing 4 elements over Rational Field + To: Incidence algebra of Finite lattice containing 4 elements over Rational Field + sage: R.an_element() - R.one() + R[(0, 0)] + 2*R[(0, 1)] + 3*R[(0, 3)] + sage: R.lift(R.an_element() - R.one()) + I[0, 0] + 2*I[0, 1] + 2*I[0, 2] + 3*I[0, 3] + I[1, 1] + + 2*I[1, 3] + I[2, 2] + 2*I[2, 3] + I[3, 3] + """ + return self.module_morphism(self._lift_basis, codomain=self._ambient) + + def __getitem__(self, A): + """ + Return the basis element indexed by ``A``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: R[0, 0] + R[(0, 0)] + sage: R[0, 1] + R[(0, 1)] + sage: R[0, 15] + R[(0, 15)] + sage: R[0] + R[(0, 0)] + + This works for any representative of the equivalence class:: + + sage: R[3, 3] + R[(0, 0)] + sage: R[3, 11] + R[(0, 1)] + """ + if not isinstance(A, (list, tuple)): + if A not in self._ambient._poset.list(): + raise ValueError("not an element of the poset") + return self.one() + else: + A = tuple(A) + if len(A) != 2: + raise ValueError("not an interval") + for k in self._equiv_classes: + if A in self._equiv_classes[k]: + return self.monomial(k) + raise ValueError("not an interval") + + def _retract(self, x): + """ + Return the retract of ``x`` from the incidence algebra to ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: I = P.incidence_algebra(QQ) + sage: R = I.reduced_subalgebra() + sage: all(R._retract(R.lift(x)) == x for x in R.basis()) + True + sage: R._retract(I.zeta()) == R.zeta() + True + sage: R._retract(I.delta()) == R.delta() + True + sage: R._retract(I.mobius()) == R.mobius() + True + """ + return self.sum_of_terms((k, x[k]) for k in self.basis().keys()) + + class Element(CombinatorialFreeModule.Element): + """ + An element of a reduced incidence algebra. + """ + def __call__(self, x, y): + """ + Return ``self(x, y)``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: x = R.an_element() + sage: x(0, 7) + 0 + sage: x(7, 15) + 2 + sage: x(4, 15) + 0 + """ + return self.parent().lift(self)(x, y) + + def _mul_(self, other): + """ + Return the product of ``self`` and ``other``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: x = R.an_element() + sage: x * R.zeta() + 2*R[(0, 0)] + 4*R[(0, 1)] + 9*R[(0, 3)] + 17*R[(0, 7)] + 28*R[(0, 15)] + sage: x * R.mobius() + 2*R[(0, 0)] + R[(0, 3)] - 5*R[(0, 7)] + 12*R[(0, 15)] + sage: x * R.mobius() * R.zeta() == x + True + """ + P = self.parent() + return P._retract(P.lift(self) * P.lift(other)) + + @cached_method + def to_matrix(self): + r""" + Return ``self`` as a matrix. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: mu = R.mobius() + sage: mu.to_matrix() + [ 1 -1 -1 1] + [ 0 1 0 -1] + [ 0 0 1 -1] + [ 0 0 0 1] + """ + return self.parent().lift(self).to_matrix() + + def is_unit(self): + """ + Return if ``self`` is a unit. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: x = R.an_element() + sage: x.is_unit() + True + """ + return self[self.parent().one_basis()].is_unit() + + def __invert__(self): + """ + Return the inverse of ``self``. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(4) + sage: R = P.incidence_algebra(QQ).reduced_subalgebra() + sage: x = R.an_element() + sage: ~x + 1/2*R[(0, 0)] - 1/2*R[(0, 1)] + 1/4*R[(0, 3)] + + 3/2*R[(0, 7)] - 33/4*R[(0, 15)] + """ + P = self.parent() + return P._retract(P.lift(self).__invert__()) + + def lift(self): + """ + Return the lift of ``self`` to the ambient space. + + EXAMPLES:: + + sage: P = posets.BooleanLattice(2) + sage: I = P.incidence_algebra(QQ) + sage: R = I.reduced_subalgebra() + sage: x = R.an_element(); x + 2*R[(0, 0)] + 2*R[(0, 1)] + 3*R[(0, 3)] + sage: x.lift() + 2*I[0, 0] + 2*I[0, 1] + 2*I[0, 2] + 3*I[0, 3] + 2*I[1, 1] + + 2*I[1, 3] + 2*I[2, 2] + 2*I[2, 3] + 2*I[3, 3] + """ + return self.parent().lift(self) + From a539b9953f9d8ccbbda67fc5b60a9372079a3eaf Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Tue, 23 Dec 2014 13:15:18 +0100 Subject: [PATCH 075/665] trac #17464: Graph automorphism groups through bliss --- src/module_list.py | 11 ++ src/sage/graphs/bliss.pyx | 283 +++++++++++++++++++++++++++++++ src/sage/graphs/generic_graph.py | 111 +++++++++--- 3 files changed, 386 insertions(+), 19 deletions(-) create mode 100644 src/sage/graphs/bliss.pyx diff --git a/src/module_list.py b/src/module_list.py index 0684b954b7c..381db586d9f 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -2210,6 +2210,17 @@ def uname_specific(name, value, alternative): language = "c++")) # libraries = ["mcqd"])) +# FIXME maybe the problem is that I didn't actually install the package +# as one would do in sage? +if is_package_installed('bliss'): + ext_modules.append( + Extension("sage.graphs.bliss", + ["sage/graphs/bliss.pyx"], + language = "c++", + libraries= ["bliss"]) + ) + +# # Only include darwin_utilities on OS_X >= 10.5 UNAME = os.uname() diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx new file mode 100644 index 00000000000..7e9d85653bc --- /dev/null +++ b/src/sage/graphs/bliss.pyx @@ -0,0 +1,283 @@ +r""" + +Interface for graph automorphisms with bliss. + +Implemented functions: + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`automorphism_group` | Returns the automorphism group of the given (di)graph + :meth:`canonical_form` | Computes a canonical certificate for the given (di) graph. + :meth:`is_isomorpic` | Tests whether the passed (di) graphs are isomorphic. + + +AUTHORS: + + - Jernej Azarija + +""" +include "sage/ext/interrupt.pxi" +include 'sage/ext/stdsage.pxi' +include 'sage/ext/cdefs.pxi' + +cdef extern from "graph.hh" namespace "bliss": + + cdef cppclass Stats: + + pass + + cdef cppclass AbstractGraph: + pass + + cdef cppclass Graph(AbstractGraph): + Graph(const unsigned int) + void add_edge(const unsigned int, const unsigned int) + void find_automorphisms(Stats&, void (*)(void* , unsigned int, + const unsigned int*), void*) + void change_color(const unsigned int, const unsigned int); + const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, + const unsigned int*), void*) + + cdef cppclass Digraph(AbstractGraph): + + Digraph(const unsigned int) + void add_edge(const unsigned int, const unsigned int) + void find_automorphisms(Stats&, void (*)(void* , unsigned int, + const unsigned int*), void*) + void change_color(const unsigned int, const unsigned int); + const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, + const unsigned int*), void*) + unsigned int get_hash() + + +cdef void add_gen(void *user_param, unsigned int n, const unsigned int *aut): + + covered = cur = 0 + perm = [] + done = [False]*n + + gens, d2 = user_param + + while covered < n: + while cur < n and done[cur]: + cur+=1 + + cycle = [d2[aut[cur]]] + sec = aut[aut[cur]] + done[aut[cur]] = done[cur] = True + + covered+=1 + + while d2[sec] != cycle[0]: + cycle.append(d2[sec]) + done[sec] = True + sec = aut[sec] + covered+=1 + perm+=[tuple(cycle)] + gens += [perm] + +# The function accepts a graph, a coloring of its vertices (possibly None) +# and two empty dictionaries. The entries of the dicitionary are later set +# to record the labeling of our graph. They are taken as arguments to avoid +# technicalities of returning Python objects in Cython functions. +cdef Graph *bliss_graph(G, partition, vert2int, int2vert): + + cdef Graph *g = new Graph(G.order()) + + if g == NULL: + raise MemoryError("Allocation Failed") + + for i,v in enumerate(G): + vert2int[v] = i + int2vert[i] = v + + for x,y in G.edges(labels=False): + g.add_edge(vert2int[x],vert2int[y]) + + if partition: + for i in xrange(1,len(partition)): + for v in partition[i]: + g.change_color(vert2int[v], i) + return g + +# This is the same function as bliss_graph with the only exception +# being that it returns a digraph. This code duplication is of course +# ugly and I am open for suggestions (that do not waste time) +cdef Digraph *bliss_digraph(G, partition, vert2int, int2vert): + + cdef Digraph *g = new Digraph(G.order()) + + for i,v in enumerate(G): + vert2int[v] = i + int2vert[i] = v + + if g == NULL: + raise MemoryError("Allocation Failed") + + for x,y in G.edges(labels=False): + g.add_edge(vert2int[x],vert2int[y]) + + if partition: + for i in xrange(1,len(partition)): + for v in partition[i]: + g.change_color(vert2int[v], i) + return g + +def automorphism_group(G, partition=None): + """ + Computes the automorphism group of ``G`` subject to the coloring ``partition.`` + + INPUT: + + - ``G`` -- A graph + - ``partition`` -- A partition of the vertices of ``G`` into color classes. + Defaults to ``none``. + + TESTS:: + + sage: from sage.graphs.bliss import automorphism_group # optional - bliss + sage: G = graphs.PetersenGraph() # optional - bliss + sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss + True # optional - bliss + + sage: G = graphs.HeawoodGraph() # optional - bliss + sage: p = G.bipartite_sets() # optional - bliss + sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss + sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss + True # optional - bliss + """ + + cv = 0 + n = G.order() + vert2int = {} + int2vert = {} + + cdef Graph *g = NULL + cdef Digraph *d = NULL + cdef Stats s + + gens = [] + data = (gens, int2vert) + + if G.is_directed(): + d = bliss_digraph(G, partition, vert2int, int2vert) + d.find_automorphisms(s, add_gen, data) + else: + g = bliss_graph(G, partition, vert2int, int2vert) + g.find_automorphisms(s, add_gen, data) + del g + del d + + from sage.groups.perm_gps.permgroup import PermutationGroup + + return PermutationGroup(gens,domain=G) + +cdef void empty_hook(void *user_param , unsigned int n, const unsigned int *aut): + return + +def canonical_form(G, partition=None, return_graph=False, certify=False): + """ + Returns a Python object such that two graphs ``G`` and ``H`` are + isomorphic if and only if canonical_form(G) == canonical_form(H). + + INPUT: + + - ``G`` -- A graph or digraph. + - ``partition`` -- A partition of the vertices of ``G`` into color classes. + Defaults to ``none``. + - ``return_graph`` -- If set to True, canonical_form returns the canonical graph + of G. + - ``certify`` -- If set to True returns the labeling of G into a canonical graph. + + TESTS:: + sage: from sage.graphs.bliss import canonical_form # optional - bliss + sage: G = graphs.PetersenGraph() # optional - bliss + sage: canonical_form(G) # optional - bliss + [(2, 0), (2, 1), (3, 0), (4, 1), (4, 6), (5, 3), (5, 4), (6, 0), + (7, 1), (7, 3), (8, 2), (8, 5), (9, 6), (9, 7), (9, 8)] # optional - bliss + + sage: P = graphs.GeneralizedPetersenGraph(5,2) # optional - bliss + sage: Q = graphs.PetersenGraph() # optional - bliss + sage: canonical_form(P) == canonical_form(Q) # optional - bliss + True + """ + cdef Graph *g = NULL + cdef Digraph *d = NULL + cdef const unsigned int *aut + cdef Stats s + + vert2int = {} + + if G.is_directed(): + d = bliss_digraph(G, partition, vert2int, {}) + aut = d.canonical_form(s, empty_hook, NULL) + else: + g = bliss_graph(G, partition, vert2int, {}) + aut = g.canonical_form(s, empty_hook, NULL) + + edges = [] + for x,y in G.edges(labels=False): + e,f = aut[ vert2int[x] ], aut[ vert2int[y] ] + edges.append( (e,f) if e > f else (f,e)) + + del g + del d + + if return_graph: + if G.is_directed(): + from sage.graphs.graph import DiGraph + G = DiGraph(edges) + else: + from sage.graphs.graph import Graph + G = Graph(edges) + + return G, vert2int if certify else G + + if certify: + return sorted(edges),vert2int + + return sorted(edges) + +# FIXME if cert=False then the best way to do this would actually +# be to compute the two canonical forms of G and H and use bliss::Graph::cmp +# which I somehow cannot make it work? Can someone look into that? +def is_isomorphic(G,H, cert=False): + """ + Tests ``G`` and ``H`` for (di) graph isomorphism. + + INPUT: + + - ``G`` -- A graph + - ``cert`` -- If set to True returns the actual isomorphism between + the vertices of ``G`` and ``H`` + + TESTS:: + + sage: from sage.graphs.bliss import is_isomorphic # optional - bliss + sage: G1 = graphs.RandomGNP(10,0.5) # optional - bliss + sage: G2 = graphs.RandomGNP(10,0.8) # optional - bliss + sage: is_isomorphic(G1,G2) + False + + sage: G = graphs.CubeGraph(3) # optional - bliss + sage: H = G.copy() # optional - bliss + sage: H.relabel() # optional - bliss + sage: is_isomorphic(G,H,cert=True) # optional - bliss + {'000': 3, '001': 2, '010': 0, '011': 1, '100': 6, '101': 7, '110': 5, '111': 4} + + """ + + + c1,lab1 = canonical_form(G, certify=True) + c2,lab2 = canonical_form(H, certify=True) + + if c1 == c2: + if cert: + lab2inv = { lab2[key]:key for key in lab2} + return { v: lab2inv[lab1[v]] for v in G} + else: + return True + return False diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 9a10f2c50ec..4655dee55b2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -212,7 +212,6 @@ :meth:`~GenericGraph.wiener_index` | Returns the Wiener index of the graph. :meth:`~GenericGraph.average_distance` | Returns the average distance between vertices of the graph. - **Flows, connectivity, trees:** .. csv-table:: @@ -17303,7 +17302,7 @@ def coarsest_equitable_refinement(self, partition, sparse=True): def automorphism_group(self, partition=None, verbosity=0, edge_labels=False, order=False, - return_group=True, orbits=False): + return_group=True, orbits=False, algorithm=None): """ Returns the largest subgroup of the automorphism group of the (di)graph whose orbit partition is finer than the partition given. @@ -17317,7 +17316,8 @@ def automorphism_group(self, partition=None, verbosity=0, respecting the partition. - ``edge_labels`` - default False, otherwise allows - only permutations respecting edge labels. + only permutations respecting edge labels. Note that this option + is not supported if ``algorithm="bliss"`` - ``order`` - (default False) if True, compute the order of the automorphism group @@ -17327,6 +17327,10 @@ def automorphism_group(self, partition=None, verbosity=0, - ``orbits`` - returns the orbits of the group acting on the vertices of the graph + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group + is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). + Note that bliss package must be installed. + .. WARNING:: Since :trac:`14319` the domain of the automorphism group is equal to @@ -17433,6 +17437,16 @@ def automorphism_group(self, partition=None, verbosity=0, sage: C.automorphism_group(orbits=True, return_group=False) [['000', '001', '010', '011', '100', '101', '110', '111']] + One can also use the faster algorithm for computing the automorphism + group of the graph - bliss:: + + sage: G = graphs.HallJankoGraph() # optional - bliss + sage: A1 = G.automorphism_group() # optional - bliss + sage: A2 = G.automorphism_group(algorithm='bliss' # optional - bliss + sage: A1.is_isomorphic(A2) # optional - bliss + True # optional - bliss + + TESTS: We get a KeyError when given an invalid partition (trac #6087):: @@ -17479,9 +17493,31 @@ def automorphism_group(self, partition=None, verbosity=0, Subgroup of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]) generated by [(0,7)(1,4)(2,3)(6,8)]] """ + from sage.misc.package import is_package_installed + if algorithm == 'bliss' and is_package_installed('bliss') and not edge_labels: + from sage.graphs.bliss import automorphism_group + + A = automorphism_group(self, partition) + + # If the user only wants the automorphism group, lets return it + # without much hassle + if return_group and not (orbits or order): + return A + + ret = [] + if order: + ret+=[A.order()] + if return_group: + ret+=[A] + if orbits: + ret+=[A.orbits()] + + return tuple(ret) + from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.groups.perm_gps.permgroup import PermutationGroup dig = (self._directed or self.has_loops()) + if partition is None: partition = [self.vertices()] if edge_labels or self.has_multiple_edges(): @@ -17707,7 +17743,7 @@ def is_hamiltonian(self): except EmptySetError: return False - def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): + def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, algorithm=None): """ Tests for isomorphism between self and other. @@ -17720,6 +17756,9 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): - ``edge_labels`` - default False, otherwise allows only permutations respecting edge labels. + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group + is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). + Note that bliss package must be installed. EXAMPLES: Graphs:: @@ -17794,6 +17833,13 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): sage: G.is_isomorphic(H, edge_labels=True, certify=True) (True, {0: 1, 1: 2, 2: 3, 3: 4, 4: 0}) + Isomorphism testing using the software Bliss is supported as well:: + + sage: G = graphs.PetersenGraph() # optional - bliss + sage: G.is_isomorphic(graphs.GeneralizedPetersenGraph(5,2),algorithm='bliss')# optional - bliss + True # optional - bliss + + TESTS:: sage: g1 = '~?A[~~{ACbCwV_~__OOcCW_fAA{CF{CCAAAC__bCCCwOOV___~____OOOOcCCCW___fAAAA'+\ @@ -17904,20 +17950,25 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): sage: g.is_isomorphic(h) True """ - from sage.groups.perm_gps.partn_ref.refinement_graphs import isomorphic - possible = True - if self.num_verts() == 0 and other.num_verts() == 0: + + if self.order() == other.order() == 0: return True - if self._directed != other._directed: - possible = False - if self.order() != other.order(): - possible = False - if self.size() != other.size(): - possible = False - if not possible and certify: - return False, None - elif not possible: - return False + + if (self.is_directed() != other.is_directed() or self.order() != other.order() or + self.size() != other.size() or self.degree_sequence() != other.degree_sequence()): + if certify: + return False,None + else: + return False + + from sage.misc.package import is_package_installed + if algorithm == 'bliss' and is_package_installed("bliss") and not edge_labels: + from sage.graphs.bliss import is_isomorphic + + return is_isomorphic(self, other, certify) + + from sage.groups.perm_gps.partn_ref.refinement_graphs import isomorphic + self_vertices = self.vertices() other_vertices = other.vertices() if edge_labels or self.has_multiple_edges(): @@ -17982,7 +18033,8 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False): isom_trans[v] = other_vertices[isom[G_to[v]]] return True, isom_trans - def canonical_label(self, partition=None, certify=False, verbosity=0, edge_labels=False): + def canonical_label(self, partition=None, certify=False, verbosity=0, + edge_labels=False,algorithm=None,return_graph=True): """ Returns the unique graph on `\{0,1,...,n-1\}` ( ``n = self.order()`` ) which @@ -18015,6 +18067,12 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, edge_label - ``edge_labels`` - default False, otherwise allows only permutations respecting edge labels. + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group + is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). + Note that bliss package must be installed. NOTE. Make sure you always compare + canonical forms obtained by the same algorithm. + + - ``return_graph`` - If ``return_graph = 'False'`` do not return the canonical graph. EXAMPLES:: @@ -18069,7 +18127,22 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, edge_label Graph on 3 vertices sage: C.vertices() [0, 1, 2] - """ + + Canonical forms can be computed by bliss as well:: + + sage: G = graphs.CubeGraph(6) # optional - bliss + sage: H = G.copy() # optional - bliss + sage: s1 = G.canonical_label(return_graph=false,algorithm='bliss') # optional - bliss + sage: s2 = H.canonical_label(return_graph=false,algorithm='bliss') # optional - bliss + sage: s1 == s2 # optional - bliss + True # optional - bliss + """ + from sage.misc.package import is_package_installed + if algorithm == 'bliss' and is_package_installed('bliss') and not edge_labels: + from sage.graphs.bliss import canonical_form + + return canonical_form(self, partition, return_graph, certify) + from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree dig = (self.has_loops() or self._directed) From 7e6edd0ecf50e7d75876b619a9495c8f57b92971 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 14 Jan 2015 13:59:15 +0530 Subject: [PATCH 076/665] trac #17464: Make IncidenceStructure.automorphism_group call Graph.automorphism_group --- .../combinat/designs/incidence_structures.py | 22 ++++++++++--------- src/sage/graphs/bliss.pyx | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 5f3d9c68e7d..fa7f9e19e86 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1308,19 +1308,21 @@ def automorphism_group(self): sage: designs.IncidenceStructure([[(1,2),(3,4)]]).automorphism_group() Permutation Group with generators [((1,2),(3,4))] """ - from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct + from sage.graphs.graph import Graph from sage.groups.perm_gps.permgroup import PermutationGroup - from sage.groups.perm_gps.permgroup_element import standardize_generator - from sage.groups.perm_gps.permgroup_named import SymmetricGroup - M1 = self.incidence_matrix().transpose() - M2 = MatrixStruct(M1) - M2.run() - gens = M2.automorphism_group()[0] - gens = [standardize_generator([x+1 for x in g]) for g in gens] + g = Graph() + n = self.num_points() + g.add_edges((i+n,x) for i,b in enumerate(self._blocks) for x in b) + ag = g.automorphism_group(partition=[range(n), range(n,n+self.num_blocks())]) + if self._point_to_index: - gens = [[tuple([self._points[i-1] for i in cycle]) for cycle in g] for g in gens] + gens = [[tuple([self._points[i] for i in cycle if (not cycle or cycle[0] Date: Wed, 14 Jan 2015 23:51:12 +0530 Subject: [PATCH 077/665] trac #17464: Additional documentation --- src/module_list.py | 7 +- src/sage/graphs/bliss.pyx | 234 +++++++++++++++++++------------ src/sage/graphs/generic_graph.py | 91 ++++++++---- 3 files changed, 208 insertions(+), 124 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 381db586d9f..3c64b85258b 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -2210,17 +2210,14 @@ def uname_specific(name, value, alternative): language = "c++")) # libraries = ["mcqd"])) -# FIXME maybe the problem is that I didn't actually install the package -# as one would do in sage? -if is_package_installed('bliss'): +if is_package_installed('bliss'): ext_modules.append( Extension("sage.graphs.bliss", ["sage/graphs/bliss.pyx"], language = "c++", libraries= ["bliss"]) ) - -# + # Only include darwin_utilities on OS_X >= 10.5 UNAME = os.uname() diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 817e21e2117..0ddd553d9d0 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -1,6 +1,5 @@ r""" - -Interface for graph automorphisms with bliss. +Interface with bliss: graph (iso/auto)morphism Implemented functions: @@ -10,13 +9,13 @@ Implemented functions: :delim: | :meth:`automorphism_group` | Returns the automorphism group of the given (di)graph - :meth:`canonical_form` | Computes a canonical certificate for the given (di) graph. - :meth:`is_isomorpic` | Tests whether the passed (di) graphs are isomorphic. + :meth:`canonical_form` | Computes a canonical certificate for the given (di) graph. + :meth:`is_isomorphic` | Tests whether the passed (di) graphs are isomorphic. AUTHORS: - - Jernej Azarija + - Jernej Azarija """ include "sage/ext/interrupt.pxi" @@ -26,76 +25,102 @@ include 'sage/ext/cdefs.pxi' cdef extern from "graph.hh" namespace "bliss": cdef cppclass Stats: - pass - + cdef cppclass AbstractGraph: pass cdef cppclass Graph(AbstractGraph): Graph(const unsigned int) void add_edge(const unsigned int, const unsigned int) - void find_automorphisms(Stats&, void (*)(void* , unsigned int, + void find_automorphisms(Stats&, void (*)(void* , unsigned int, const unsigned int*), void*) void change_color(const unsigned int, const unsigned int); - const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, + const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, const unsigned int*), void*) cdef cppclass Digraph(AbstractGraph): Digraph(const unsigned int) void add_edge(const unsigned int, const unsigned int) - void find_automorphisms(Stats&, void (*)(void* , unsigned int, + void find_automorphisms(Stats&, void (*)(void* , unsigned int, const unsigned int*), void*) void change_color(const unsigned int, const unsigned int); - const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, + const unsigned int* canonical_form(Stats&, void (*)(void*,unsigned int, const unsigned int*), void*) unsigned int get_hash() cdef void add_gen(void *user_param, unsigned int n, const unsigned int *aut): + r""" + This function is called each time a new generator of the automorphism group + is found. + + This function is used to append the new generators to a Python list. Its + main job is to translate a permutation into dijoint cycles. + + INPUT: + + - ``user_param`` (``void *``) -- in the current implementation, it points + toward a Python object which is a pair + ``(list_of_current_generators,vert_to_integer_labelling)``. - covered = cur = 0 - perm = [] - done = [False]*n + - ``n`` (int) -- number of points in the graph. - gens, d2 = user_param - - while covered < n: + - ``aut`` (int *) -- an automorphism of the graph. + """ + cdef int tmp = 0 + cdef int marker = 0 + cdef int cur = 0 + perm = [] + done = [False]*n + + gens, int_to_vertex = user_param + + while True: while cur < n and done[cur]: cur+=1 + if cur == n: + break - cycle = [d2[aut[cur]]] - sec = aut[aut[cur]] - done[aut[cur]] = done[cur] = True + marker = tmp = cur + cycle = [int_to_vertex[cur]] + done[cur] = True - covered+=1 + while aut[tmp] != marker: + tmp = aut[tmp] + done[tmp] = True + cycle.append(int_to_vertex[tmp]) - while d2[sec] != cycle[0]: - cycle.append(d2[sec]) - done[sec] = True - sec = aut[sec] - covered+=1 - perm+=[tuple(cycle)] - gens += [perm] + perm.append(tuple(cycle)) + gens.append(perm) -# The function accepts a graph, a coloring of its vertices (possibly None) -# and two empty dictionaries. The entries of the dicitionary are later set -# to record the labeling of our graph. They are taken as arguments to avoid -# technicalities of returning Python objects in Cython functions. -cdef Graph *bliss_graph(G, partition, vert2int, int2vert): +cdef Graph *bliss_graph(G, partition, vert2int, int2vert): + r""" + Return a bliss copy of a graph G + + INPUT: + - ``G`` (a graph) + + - ``partition`` -- a partition of the vertex set. + + - ``vert2int, int2vert`` -- Two empty dictionaries. The entries of the + dicitionary are later set to record the labeling of our graph. They are + taken as arguments to avoid technicalities of returning Python objects in + Cython functions. + """ cdef Graph *g = new Graph(G.order()) if g == NULL: raise MemoryError("Allocation Failed") - for i,v in enumerate(G): + for i,v in enumerate(G.vertices()): vert2int[v] = i - int2vert[i] = v + int2vert[i] = v for x,y in G.edges(labels=False): - g.add_edge(vert2int[x],vert2int[y]) + g.add_edge(vert2int[x],vert2int[y]) if partition: for i in xrange(1,len(partition)): @@ -103,22 +128,32 @@ cdef Graph *bliss_graph(G, partition, vert2int, int2vert): g.change_color(vert2int[v], i) return g -# This is the same function as bliss_graph with the only exception -# being that it returns a digraph. This code duplication is of course -# ugly and I am open for suggestions (that do not waste time) -cdef Digraph *bliss_digraph(G, partition, vert2int, int2vert): +cdef Digraph *bliss_digraph(G, partition, vert2int, int2vert): + r""" + Return a bliss copy of a digraph G + + INPUT: + + - ``G`` (a digraph) + + - ``partition`` -- a partition of the vertex set. - cdef Digraph *g = new Digraph(G.order()) + - ``vert2int, int2vert`` -- Two empty dictionaries. The entries of the + dicitionary are later set to record the labeling of our graph. They are + taken as arguments to avoid technicalities of returning Python objects in + Cython functions. + """ + cdef Digraph *g = new Digraph(G.order()) - for i,v in enumerate(G): + for i,v in enumerate(G.vertices()): vert2int[v] = i - int2vert[i] = v - + int2vert[i] = v + if g == NULL: raise MemoryError("Allocation Failed") for x,y in G.edges(labels=False): - g.add_edge(vert2int[x],vert2int[y]) + g.add_edge(vert2int[x],vert2int[y]) if partition: for i in xrange(1,len(partition)): @@ -128,29 +163,30 @@ cdef Digraph *bliss_digraph(G, partition, vert2int, int2vert): def automorphism_group(G, partition=None): """ - Computes the automorphism group of ``G`` subject to the coloring ``partition.`` + Computes the automorphism group of ``G`` subject to the coloring ``partition.`` INPUT: - ``G`` -- A graph - - ``partition`` -- A partition of the vertices of ``G`` into color classes. - Defaults to ``none``. + + - ``partition`` -- A partition of the vertices of ``G`` into color classes. + Defaults to ``None``, which is equivalent to a partition of size 1. TESTS:: sage: from sage.graphs.bliss import automorphism_group # optional - bliss sage: G = graphs.PetersenGraph() # optional - bliss sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss - True # optional - bliss + True sage: G = graphs.HeawoodGraph() # optional - bliss sage: p = G.bipartite_sets() # optional - bliss sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss - True # optional - bliss + True """ - cv = 0 + cv = 0 n = G.order() vert2int = {} int2vert = {} @@ -159,20 +195,19 @@ def automorphism_group(G, partition=None): cdef Digraph *d = NULL cdef Stats s - gens = [] - data = (gens, int2vert) + gens = [] + data = (gens, int2vert) - if G.is_directed(): + if G.is_directed(): d = bliss_digraph(G, partition, vert2int, int2vert) d.find_automorphisms(s, add_gen, data) + del d else: - g = bliss_graph(G, partition, vert2int, int2vert) + g = bliss_graph(G, partition, vert2int, int2vert) g.find_automorphisms(s, add_gen, data) - del g - del d + del g from sage.groups.perm_gps.permgroup import PermutationGroup - return PermutationGroup(gens,domain=G) cdef void empty_hook(void *user_param , unsigned int n, const unsigned int *aut): @@ -180,51 +215,65 @@ cdef void empty_hook(void *user_param , unsigned int n, const unsigned int *aut) def canonical_form(G, partition=None, return_graph=False, certify=False): """ - Returns a Python object such that two graphs ``G`` and ``H`` are - isomorphic if and only if canonical_form(G) == canonical_form(H). + Return a canonical label of ``G`` + + A canonical label ``canonical_form(G)`` of ``G`` is a (di)graph defined on + `\{0,...,n-1\}` such that ``G`` is isomorphic to ``H`` if and only if + ``canonical_form(G)`` is equal to ``canonical_form(H)``. INPUT: - ``G`` -- A graph or digraph. - - ``partition`` -- A partition of the vertices of ``G`` into color classes. - Defaults to ``none``. - - ``return_graph`` -- If set to True, canonical_form returns the canonical graph - of G. - - ``certify`` -- If set to True returns the labeling of G into a canonical graph. + + - ``partition`` -- A partition of the vertices of ``G`` into color classes. + Defaults to ``None``. + + - ``return_graph`` -- If set to ``True``, ``canonical_form`` returns the + canonical graph of G. Otherwise, it returns its set of edges. + + - ``certify`` -- If set to ``True`` returns the labeling of G into a + canonical graph. TESTS:: + sage: from sage.graphs.bliss import canonical_form # optional - bliss sage: G = graphs.PetersenGraph() # optional - bliss sage: canonical_form(G) # optional - bliss - [(2, 0), (2, 1), (3, 0), (4, 1), (4, 6), (5, 3), (5, 4), (6, 0), - (7, 1), (7, 3), (8, 2), (8, 5), (9, 6), (9, 7), (9, 8)] # optional - bliss - + [(2, 0), (2, 1), (3, 0), (4, 1), (5, 3), (5, 4), (6, 0), (6, 4), + (7, 1), (7, 3), (8, 2), (8, 5), (9, 6), (9, 7), (9, 8)] + sage: P = graphs.GeneralizedPetersenGraph(5,2) # optional - bliss sage: Q = graphs.PetersenGraph() # optional - bliss sage: canonical_form(P) == canonical_form(Q) # optional - bliss True + + sage: canonical_form(Graph(15),return_graph=True) # optional - bliss + Graph on 15 vertices + sage: g = digraphs.RandomTournament(40) # optional - bliss + sage: g.is_isomorphic(canonical_form(g,return_graph=True)) # optional - bliss + True """ - cdef Graph *g = NULL - cdef Digraph *d = NULL cdef const unsigned int *aut + cdef Graph *g = NULL + cdef Digraph *d = NULL cdef Stats s vert2int = {} - + if G.is_directed(): - d = bliss_digraph(G, partition, vert2int, {}) + d = bliss_digraph(G, partition, vert2int, {}) aut = d.canonical_form(s, empty_hook, NULL) + edges = [(aut[ vert2int[x] ], aut[ vert2int[y] ]) + for x,y in G.edges(labels=False)] + del d else: g = bliss_graph(G, partition, vert2int, {}) - aut = g.canonical_form(s, empty_hook, NULL) - - edges = [] - for x,y in G.edges(labels=False): - e,f = aut[ vert2int[x] ], aut[ vert2int[y] ] - edges.append( (e,f) if e > f else (f,e)) - - del g - del d + aut = g.canonical_form(s, empty_hook, NULL) + edges = [] + for x,y in G.edges(labels=False): + e,f = aut[ vert2int[x] ], aut[ vert2int[y] ] + edges.append( (e,f) if e > f else (f,e)) + del g if return_graph: if G.is_directed(): @@ -234,7 +283,8 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): from sage.graphs.graph import Graph G = Graph(edges) - return G, vert2int if certify else G + G.add_vertices(vert2int.values()) + return (G, vert2int) if certify else G if certify: return sorted(edges),vert2int @@ -251,8 +301,8 @@ def is_isomorphic(G,H, cert=False): INPUT: - ``G`` -- A graph - - ``cert`` -- If set to True returns the actual isomorphism between - the vertices of ``G`` and ``H`` + - ``cert`` -- If set to True returns the actual isomorphism between + the vertices of ``G`` and ``H`` TESTS:: @@ -266,18 +316,22 @@ def is_isomorphic(G,H, cert=False): sage: H = G.copy() # optional - bliss sage: H.relabel() # optional - bliss sage: is_isomorphic(G,H,cert=True) # optional - bliss - {'000': 3, '001': 2, '010': 0, '011': 1, '100': 6, '101': 7, '110': 5, '111': 4} - + {'000': 0, + '001': 1, + '010': 2, + '011': 3, + '100': 4, + '101': 5, + '110': 6, + '111': 7} """ - - c1,lab1 = canonical_form(G, certify=True) c2,lab2 = canonical_form(H, certify=True) - + if c1 == c2: if cert: lab2inv = { lab2[key]:key for key in lab2} return { v: lab2inv[lab1[v]] for v in G} else: return True - return False + return False diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 4655dee55b2..0846a1a1f9a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17327,9 +17327,11 @@ def automorphism_group(self, partition=None, verbosity=0, - ``orbits`` - returns the orbits of the group acting on the vertices of the graph - - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group - is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). - Note that bliss package must be installed. + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is + computed using the optional package bliss + (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). Setting it to + "sage" uses Sage's implementation. If set to ``None`` (default), + bliss is used when available. .. WARNING:: @@ -17437,16 +17439,15 @@ def automorphism_group(self, partition=None, verbosity=0, sage: C.automorphism_group(orbits=True, return_group=False) [['000', '001', '010', '011', '100', '101', '110', '111']] - One can also use the faster algorithm for computing the automorphism + One can also use the faster algorithm for computing the automorphism group of the graph - bliss:: sage: G = graphs.HallJankoGraph() # optional - bliss sage: A1 = G.automorphism_group() # optional - bliss - sage: A2 = G.automorphism_group(algorithm='bliss' # optional - bliss + sage: A2 = G.automorphism_group(algorithm='bliss') # optional - bliss sage: A1.is_isomorphic(A2) # optional - bliss True # optional - bliss - TESTS: We get a KeyError when given an invalid partition (trac #6087):: @@ -17494,25 +17495,39 @@ def automorphism_group(self, partition=None, verbosity=0, """ from sage.misc.package import is_package_installed - if algorithm == 'bliss' and is_package_installed('bliss') and not edge_labels: - from sage.graphs.bliss import automorphism_group - - A = automorphism_group(self, partition) + if (algorithm == 'bliss' or # explicit choice from the user; or + (algorithm is None and # by default + not edge_labels and + is_package_installed('bliss'))): + if edge_labels: + raise ValueError("bliss cannot be used when edge_labels is True") + try: + from sage.graphs.bliss import automorphism_group + except ImportError: + raise ImportError("You must install the 'bliss' package to run this command.") + + A = automorphism_group(self, partition) # If the user only wants the automorphism group, lets return it # without much hassle if return_group and not (orbits or order): return A - + ret = [] - if order: - ret+=[A.order()] if return_group: - ret+=[A] + ret.append(A) + if order: + ret.append(A.order()) if orbits: - ret+=[A.orbits()] - - return tuple(ret) + ret.append(A.orbits()) + + if return_group + order + orbits == 1: + return ret[0] + return ret + + if (algorithm is not None and + algorithm != "sage"): + raise ValueError("'algorithm' must be equal to 'bliss', 'sage', or None") from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.groups.perm_gps.permgroup import PermutationGroup @@ -18033,10 +18048,9 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, al isom_trans[v] = other_vertices[isom[G_to[v]]] return True, isom_trans - def canonical_label(self, partition=None, certify=False, verbosity=0, + def canonical_label(self, partition=None, certify=False, verbosity=0, edge_labels=False,algorithm=None,return_graph=True): - """ - Returns the unique graph on `\{0,1,...,n-1\}` ( ``n = self.order()`` ) which + """Return a graph on `\{0,1,...,n-1\}` ( ``n = self.order()`` ) which - is isomorphic to self, @@ -18067,12 +18081,19 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, - ``edge_labels`` - default False, otherwise allows only permutations respecting edge labels. - - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group - is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). - Note that bliss package must be installed. NOTE. Make sure you always compare - canonical forms obtained by the same algorithm. + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is + computed using the optional package bliss + (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). Setting it to + "sage" uses Sage's implementation. If set to ``None`` (default), + bliss is used when available. - - ``return_graph`` - If ``return_graph = 'False'`` do not return the canonical graph. + .. NOTE:: + + Make sure you always compare canonical forms obtained by the + same algorithm. + + - ``return_graph`` - If ``return_graph = 'False'`` do not return the + canonical graph. EXAMPLES:: @@ -18129,20 +18150,32 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, [0, 1, 2] Canonical forms can be computed by bliss as well:: - + sage: G = graphs.CubeGraph(6) # optional - bliss sage: H = G.copy() # optional - bliss sage: s1 = G.canonical_label(return_graph=false,algorithm='bliss') # optional - bliss sage: s2 = H.canonical_label(return_graph=false,algorithm='bliss') # optional - bliss sage: s1 == s2 # optional - bliss True # optional - bliss + """ from sage.misc.package import is_package_installed - if algorithm == 'bliss' and is_package_installed('bliss') and not edge_labels: - from sage.graphs.bliss import canonical_form - + if (algorithm == 'bliss' or # explicit request; or + (algorithm is None and # default choice + is_package_installed('bliss') and + not edge_labels)): + if edge_labels: + raise ValueError("bliss cannot be used when edge_labels is True") + try: + from sage.graphs.bliss import canonical_form + except ImportError: + raise ImportError("You must install the 'bliss' package to run this command.") return canonical_form(self, partition, return_graph, certify) + if (algorithm is not None and + algorithm != "sage"): + raise ValueError("'algorithm' must be equal to 'bliss', 'sage', or None") + from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree dig = (self.has_loops() or self._directed) From 2403caefd14045de2a83bbc33a230340e1d49130 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Fri, 23 Jan 2015 21:37:38 +0100 Subject: [PATCH 078/665] Trac 17664: fix permutation group domain for subgroups of Galois groups --- src/sage/rings/number_field/galois_group.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 1e14977a0b2..f75cbfcb852 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -562,9 +562,23 @@ def __init__(self, ambient, elts): sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group() sage: GaloisGroup_subgroup( G, [ G(1), G([(1,2,3),(4,5,6)]), G([(1,3,2),(4,6,5)])]) Subgroup [(), (1,2,3)(4,5,6), (1,3,2)(4,6,5)] of Galois group of Number Field in b with defining polynomial x^6 - 6*x^4 + 9*x^2 + 23 + + TESTS: + + Check that :trac:`17664` is fixed:: + + sage: L. = QuadraticField(-1) + sage: P = L.primes_above(5)[0] + sage: G = L.galois_group() + sage: H = G.decomposition_group(P) + sage: H.domain() + {1, 2} + sage: G.artin_symbol(P) + () """ #XXX: This should be fixed so that this can use GaloisGroup_v2.__init__ - PermutationGroup_generic.__init__(self, elts, canonicalize = True) + PermutationGroup_generic.__init__(self, elts, canonicalize=True, + domain=ambient.domain()) self._ambient = ambient self._number_field = ambient.number_field() self._galois_closure = ambient._galois_closure From 97bb760e17aefff7c9004bcad17409627d94e99d Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 13:42:43 +0100 Subject: [PATCH 079/665] Added correct fix for digraph's missing heuristic --- .../bliss/patches/digraph_heuristic.patch | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/build/pkgs/bliss/patches/digraph_heuristic.patch b/build/pkgs/bliss/patches/digraph_heuristic.patch index a8f0481d4bf..c1b154900bc 100644 --- a/build/pkgs/bliss/patches/digraph_heuristic.patch +++ b/build/pkgs/bliss/patches/digraph_heuristic.patch @@ -1,11 +1,10 @@ ---- bliss-0.72/graph.hh 2011-05-12 15:29:46.000000000 +0200 -+++ /home/azi/bliss-0.72/graph.hh 2014-12-30 11:14:20.917059666 +0100 -@@ -843,7 +843,7 @@ - bool is_equitable() const; +--- bliss-0.72/graph.cc 2011-05-12 15:29:46.000000000 +0200 ++++ /tmp/bliss-0.72/graph.cc 2015-01-28 13:40:42.289179859 +0100 +@@ -1920,6 +1920,7 @@ + Digraph::Digraph(const unsigned int nof_vertices) + { + vertices.resize(nof_vertices); ++ sh = shs_f; + } + - /* Splitting heuristics, documented in more detail in the cc-file. */ -- SplittingHeuristic sh; -+ SplittingHeuristic sh = shs_f; - Partition::Cell* find_next_cell_to_be_splitted(Partition::Cell *cell); - Partition::Cell* sh_first(); - Partition::Cell* sh_first_smallest(); From 9a84f54d2877fa89083dfade62c5ff243f4bca31 Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 14:13:28 +0100 Subject: [PATCH 080/665] Fixed test cases so that all tests pass. --- src/sage/graphs/generic_graph.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 0846a1a1f9a..21bd2024128 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17431,12 +17431,12 @@ def automorphism_group(self, partition=None, verbosity=0, :: sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, orbits=True) + sage: G.automorphism_group(return_group=False, orbits=True,algorithm='sage') [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] - sage: G.automorphism_group(partition=[[0],range(1,10)], return_group=False, orbits=True) + sage: G.automorphism_group(partition=[[0],range(1,10)], return_group=False, orbits=True,algorithm='sage') [[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]] sage: C = graphs.CubeGraph(3) - sage: C.automorphism_group(orbits=True, return_group=False) + sage: C.automorphism_group(orbits=True, return_group=False,algorithm='sage') [['000', '001', '010', '011', '100', '101', '110', '111']] One can also use the faster algorithm for computing the automorphism @@ -17454,19 +17454,19 @@ def automorphism_group(self, partition=None, verbosity=0, sage: g=graphs.CubeGraph(3) sage: g.relabel() - sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]]) + sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') Traceback (most recent call last): ... KeyError: 6 Labeled automorphism group:: - sage: digraphs.DeBruijn(3,2).automorphism_group() + sage: digraphs.DeBruijn(3,2).automorphism_group(algorithm='sage') Permutation Group with generators [('01','02')('10','20')('11','22')('12','21'), ('00','11')('01','10')('02','12')('20','21')] sage: d = digraphs.DeBruijn(3,2) sage: d.allow_multiple_edges(True) sage: d.add_edge(d.edges()[0]) - sage: d.automorphism_group() + sage: d.automorphism_group(algorithm='sage') Permutation Group with generators [('01','02')('10','20')('11','22')('12','21')] The labeling is correct:: @@ -18098,9 +18098,9 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, EXAMPLES:: sage: D = graphs.DodecahedralGraph() - sage: E = D.canonical_label(); E + sage: E = D.canonical_label(algorithm='sage'); E Dodecahedron: Graph on 20 vertices - sage: D.canonical_label(certify=True) + sage: D.canonical_label(certify=True,algorithm='sage') (Dodecahedron: Graph on 20 vertices, {0: 0, 1: 19, 2: 16, 3: 15, 4: 9, 5: 1, 6: 10, 7: 8, 8: 14, 9: 12, 10: 17, 11: 11, 12: 5, 13: 6, 14: 2, 15: 4, 16: 3, 17: 7, 18: 13, 19: 18}) sage: D.is_isomorphic(E) True @@ -18120,7 +18120,7 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, sage: P = graphs.PetersenGraph() sage: DP = P.to_directed() - sage: DP.canonical_label().adjacency_matrix() + sage: DP.canonical_label(algorithm='sage').adjacency_matrix() [0 0 0 0 0 0 0 1 1 1] [0 0 0 0 1 0 1 0 0 1] [0 0 0 1 0 0 1 0 1 0] From 2942c3136ffad17f490b55cd83421c70c05ff46a Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 14:20:58 +0100 Subject: [PATCH 081/665] Removed is_isomorphic --- src/sage/graphs/bliss.pyx | 45 --------------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 0ddd553d9d0..1871b47db73 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -290,48 +290,3 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): return sorted(edges),vert2int return sorted(edges) - -# FIXME if cert=False then the best way to do this would actually -# be to compute the two canonical forms of G and H and use bliss::Graph::cmp -# which I somehow cannot make it work? Can someone look into that? -def is_isomorphic(G,H, cert=False): - """ - Tests ``G`` and ``H`` for (di) graph isomorphism. - - INPUT: - - - ``G`` -- A graph - - ``cert`` -- If set to True returns the actual isomorphism between - the vertices of ``G`` and ``H`` - - TESTS:: - - sage: from sage.graphs.bliss import is_isomorphic # optional - bliss - sage: G1 = graphs.RandomGNP(10,0.5) # optional - bliss - sage: G2 = graphs.RandomGNP(10,0.8) # optional - bliss - sage: is_isomorphic(G1,G2) # optional - bliss - False - - sage: G = graphs.CubeGraph(3) # optional - bliss - sage: H = G.copy() # optional - bliss - sage: H.relabel() # optional - bliss - sage: is_isomorphic(G,H,cert=True) # optional - bliss - {'000': 0, - '001': 1, - '010': 2, - '011': 3, - '100': 4, - '101': 5, - '110': 6, - '111': 7} - """ - c1,lab1 = canonical_form(G, certify=True) - c2,lab2 = canonical_form(H, certify=True) - - if c1 == c2: - if cert: - lab2inv = { lab2[key]:key for key in lab2} - return { v: lab2inv[lab1[v]] for v in G} - else: - return True - return False From 2018dbc040e23bfafc873af17adc75f699a175cc Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 14:26:04 +0100 Subject: [PATCH 082/665] Fixed error related to the new way of computing automorphisms. --- src/sage/graphs/tutte_polynomial.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 23b02c5d6a9..c83c84110c9 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -483,7 +483,21 @@ def _cache_key(G): sage: from sage.graphs.tutte_polynomial import _cache_key sage: G = graphs.PetersenGraph() sage: _cache_key(G) - ((0, 7), (0, 8), (0, 9), (1, 4), (1, 6), (1, 9), (2, 3), (2, 6), (2, 8), (3, 5), (3, 9), (4, 5), (4, 8), (5, 7), (6, 7)) + ((0, 2), + (0, 3), + (0, 6), + (1, 2), + (1, 4), + (1, 7), + (2, 8), + (3, 5), + (3, 7), + (4, 5), + (4, 6), + (5, 8), + (6, 9), + (7, 9), + (8, 9)) """ return tuple(sorted(G.canonical_label().edges(labels=False))) From cac03d7f9ce6ee3de47ad48f46a9118fb0c72083 Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 15:23:33 +0100 Subject: [PATCH 083/665] Made sure canonical labels are computed with Sage's algorithm --- src/sage/graphs/tutte_polynomial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index c83c84110c9..053bce7f450 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -499,7 +499,7 @@ def _cache_key(G): (7, 9), (8, 9)) """ - return tuple(sorted(G.canonical_label().edges(labels=False))) + return tuple(sorted(G.canonical_label(algorithm='sage').edges(labels=False))) def _cached(func): From c68235bf3c18d02dbfa17c92578f70a71a251b32 Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 28 Jan 2015 17:12:22 +0100 Subject: [PATCH 084/665] Removed (trivial) doctest complicating bliss integration --- src/sage/graphs/tutte_polynomial.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 053bce7f450..cc4181e126b 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -477,29 +477,8 @@ def _cache_key(G): Return the key used to cache the result for the graph G This is used by the decorator :func:`_cached`. - - EXAMPLES:: - - sage: from sage.graphs.tutte_polynomial import _cache_key - sage: G = graphs.PetersenGraph() - sage: _cache_key(G) - ((0, 2), - (0, 3), - (0, 6), - (1, 2), - (1, 4), - (1, 7), - (2, 8), - (3, 5), - (3, 7), - (4, 5), - (4, 6), - (5, 8), - (6, 9), - (7, 9), - (8, 9)) """ - return tuple(sorted(G.canonical_label(algorithm='sage').edges(labels=False))) + return tuple(sorted(G.canonical_label().edges(labels=False))) def _cached(func): From 155cdf6cbc17fac37a88f87d20470c3f4eb167a4 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 10 Feb 2015 17:49:57 +0100 Subject: [PATCH 085/665] doc fixes --- src/sage/combinat/interval_posets.py | 2 +- .../combinat/species/generating_series.py | 79 ++++++++++--------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 109f2a14795..88d2a564c0c 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -1926,7 +1926,7 @@ def maximal_chain_dyck_words(self): def tamari_inversions(self): r""" Return the Tamari inversions of ``self``. A Tamari inversion is - a pair of vertices `(a,b)' with `a < b` such that: + a pair of vertices `(a,b)` with `a < b` such that: - the decreasing parent of `b` is strictly smaller than `a` (or does not exist), and diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 851706df1b2..f0475116e7d 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -84,9 +84,10 @@ @cached_function def OrdinaryGeneratingSeriesRing(R): """ - Returns the ring of ordinary generating series. + Return the ring of ordinary generating series over ``R``. - Note that is is just a LazyPowerSeriesRing whose elements have + Note that is is just a + :class:`LazyPowerSeriesRing` whose elements have some extra methods. EXAMPLES:: @@ -125,7 +126,7 @@ def __init__(self, R): class OrdinaryGeneratingSeries(LazyPowerSeries): def count(self, n): """ - Returns the number of structures on a set of size n. + Return the number of structures on a set of size ``n``. EXAMPLES:: @@ -139,8 +140,8 @@ def count(self, n): def counts(self, n): """ - Returns the number of structures on a set for size i for i in - range(n). + Return the number of structures on a set for size ``i`` for + each ``i`` in ``range(n)``. EXAMPLES:: @@ -156,8 +157,9 @@ def counts(self, n): @cached_function def ExponentialGeneratingSeriesRing(R): """ - Returns the ring of ordinary generating series. Note that is is - just a LazyPowerSeriesRing whose elements have some extra methods. + Return the ring of exponential generating series. Note that this + is just a :class:`LazyPowerSeriesRing` whose elements have some + extra methods. EXAMPLES:: @@ -194,7 +196,7 @@ def __init__(self, R): class ExponentialGeneratingSeries(LazyPowerSeries): def count(self, n): """ - Returns the number of structures of size n. + Return the number of structures of size ``n``. EXAMPLES:: @@ -208,8 +210,8 @@ def count(self, n): def counts(self, n): """ - Returns the number of structures on a set for size i for i in - range(n). + Return the number of structures on a set for size ``i`` for + each ``i`` in ``range(n)``. EXAMPLES:: @@ -223,14 +225,13 @@ def counts(self, n): def functorial_composition(self, y): r""" - Returns the exponential generating series which is the functorial - composition of self with y. + Return the exponential generating series which is the functorial + composition of ``self`` with ``y``. If `f = \sum_{n=0}^{\infty} f_n \frac{x^n}{n!}` and - `g = \sum_{n=0}^{\infty} f_n \frac{x^n}{n!}`, then + `g = \sum_{n=0}^{\infty} g_n \frac{x^n}{n!}`, then functorial composition `f \Box g` is defined as - .. math:: f \Box g = \sum_{n=0}^{\infty} f_{g_n} \frac{x^n}{n!} @@ -346,15 +347,15 @@ def __repr__(self): class CycleIndexSeries(LazyPowerSeries): def count(self, t): """ - Returns the number of structures corresponding to a certain cycle - type. + Return the number of structures corresponding to a certain cycle + type ``t``. EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() sage: CIS = CycleIndexSeriesRing(p) - sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) + sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) sage: f.count([1]) 1 sage: f.count([1,1]) @@ -367,7 +368,7 @@ def count(self, t): def coefficient_cycle_type(self, t): """ - Returns the coefficient of a cycle type t. + Returns the coefficient of a cycle type ``t`` in ``self``. EXAMPLES:: @@ -389,29 +390,29 @@ def coefficient_cycle_type(self, t): def stretch(self, k): r""" - Returns the stretch of a cycle index series by a positive integer - `k`. + Return the stretch of the cycle index series ``self`` by a positive + integer `k`. If .. math:: - f = \sum_{n=0}^{\infty} f_n(x_1, x_2, \ldots, x_n), + f = \sum_{n=0}^{\infty} f_n(p_1, p_2, p_3, \ldots ), then the stretch `g` of `f` by `k` is .. math:: - g = \sum_{n=0}^{\infty} f_n(x_k, x_{2k}, \ldots, x_{nk}). + g = \sum_{n=0}^{\infty} f_n(p_k, p_{2k}, p_{3k}, \ldots ). EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() sage: CIS = CycleIndexSeriesRing(p) - sage: f = CIS([p([1])]) + sage: f = CIS([p([]), p([1]), p([2]), p.zero()]) sage: f.stretch(3).coefficients(10) - [p[3], 0, 0, p[3], 0, 0, p[3], 0, 0, p[3]] + [p[], 0, 0, p[3], 0, 0, p[6], 0, 0, 0] """ return self._new(partial(self._stretch_gen, k), lambda ao: k*ao, self) @@ -429,7 +430,7 @@ def _stretch_gen(self, k, ao): """ from sage.combinat.partition import Partition BR = self.base_ring() - zero = BR(0) + zero = BR.zero() stretch_k = lambda p: Partition([k*i for i in p]) @@ -438,7 +439,7 @@ def _stretch_gen(self, k, ao): n = 1 while True: for i in range(k-1): - yield BR(0) + yield zero yield self.coefficient(n).map_support(stretch_k) n += 1 @@ -542,7 +543,7 @@ def _egs_gen(self, ao): def __invert__(self): """ - Return the multiplicative inverse of self. + Return the multiplicative inverse of ``self``. This algorithm is derived from [BLL]_. @@ -561,7 +562,12 @@ def __invert__(self): REFERENCES: - .. [BLL] F. Bergeron, G. Labelle, and P. Leroux. "Combinatorial species and tree-like structures". Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. + .. [BLL] F. Bergeron, G. Labelle, and P. Leroux. + "Combinatorial species and tree-like structures". + Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. + .. [BLL-Intro] Francois Bergeron, Gilbert Labelle, and Pierre Leroux. + "Introduction to the Theory of Species of Structures", March 14, 2008. + http://bergeron.math.uqam.ca/Site/bergeron_anglais_files/livre_combinatoire.pdf AUTHORS: @@ -587,7 +593,7 @@ def _div_(self, y): def functorial_composition(self, g): r""" - Returns the functorial composition of self and g. + Returns the functorial composition of ``self`` and ``g``. If `F` and `G` are species, their functorial composition is the species `F \Box G` obtained by setting `(F \Box G) [A] = F[ G[A] ]`. @@ -621,8 +627,8 @@ def functorial_composition(self, g): def _functorial_compose_gen(self, g, ao): """ - Returns s generator for the coefficients of the functorial - composition of self with g. + Return a generator for the coefficients of the functorial + composition of ``self`` with ``g``. EXAMPLES:: @@ -709,8 +715,6 @@ def arithmetic_product(self, g, check_input = True): :arXiv:`math/0503436v2`. """ - from sage.combinat.partition import Partition, Partitions - from sage.combinat.species.stream import Stream, _integers_from from sage.rings.arith import gcd, lcm, divisors from itertools import product, repeat, chain @@ -828,9 +832,12 @@ def _card(self, n): def _compose_gen(self, y, ao): """ - Returns a generator for the coefficients of the composition of this - cycle index series and the cycle index series y. This overrides the - the method defined in LazyPowerSeries. + Return a generator for the coefficients of the composition of this + cycle index series and the cycle index series ``y``. This overrides + the method defined in ``LazyPowerSeries``. + + The notion "composition" means plethystic substitution here, as + defined in Section 2.2 of [BLL-Intro]_. EXAMPLES:: From be4b5ff1cb22f8bf3280bb83751078c5ce57c30a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 10 Feb 2015 18:13:39 +0100 Subject: [PATCH 086/665] add doc to CycleIndexSeriesRing --- .../combinat/species/generating_series.py | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index f0475116e7d..f2c46150881 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -157,9 +157,11 @@ def counts(self, n): @cached_function def ExponentialGeneratingSeriesRing(R): """ - Return the ring of exponential generating series. Note that this - is just a :class:`LazyPowerSeriesRing` whose elements have some - extra methods. + Return the ring of exponential generating series over ``R``. + + Note that is is just a + :class:`LazyPowerSeriesRing` whose elements have + some extra methods. EXAMPLES:: @@ -297,16 +299,46 @@ def factorial_gen(): @cached_function def CycleIndexSeriesRing(R): - """ - Returns the ring of cycle index series. Note that is is just a - LazyPowerSeriesRing whose elements have some extra methods. + r""" + Return the ring of cycle index series over ``R``. + + This is the ring of formal power series `\Lambda[X]`, where + `\Lambda` is the ring of symmetric functions over ``R`` in the + `p`-basis. Its purpose is to house the cycle index series of + species (in a somewhat nonstandard notation tailored to Sage): + If `F` is a species, then the *cycle index series* of `F` is + defined to be the formal power series + + .. MATH:: + + \sum_{n \geq 0} \frac{1}{n!} (\sum_{\sigma \in S_n} + \operatorname{fix} F[\sigma] + \prod_{z \text{ is a cycle of } \sigma} + p_{\text{length of } z}) X^n + \in \Lambda_\QQ [X], + + where `\operatorname{fix} F[\sigma]` denotes the number of + fixed points of the permutation `F[\sigma]` of `F[n]`. We + notice that this power series is "equigraded" (meaning that + its `X^n`-coefficient is homogeneous of degree `n`). A more + standard convention in combinatorics would be to use + `x_i` instead of `p_i`, and drop the `X` (that is, evaluate + the above power series at `X = 1`); but this would be more + difficult to implement in Sage, as it would be an element + of a power series ring in infinitely many variables. + + Note that is is just a :class:`LazyPowerSeriesRing` (whose base + ring is `\Lambda`) whose elements have some extra methods. + + The EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: R = CycleIndexSeriesRing(QQ); R Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis - sage: R([1]).coefficients(4) + sage: R([1]).coefficients(4) # This is not combinatorially + ....: # meaningful. [1, 1, 1, 1] TESTS: We test to make sure that caching works. @@ -354,7 +386,7 @@ def count(self, t): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(p) + sage: CIS = CycleIndexSeriesRing(QQ) sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) sage: f.count([1]) 1 @@ -374,7 +406,7 @@ def coefficient_cycle_type(self, t): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(p) + sage: CIS = CycleIndexSeriesRing(QQ) sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) sage: f.coefficient_cycle_type([1]) 1 @@ -409,7 +441,7 @@ def stretch(self, k): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(p) + sage: CIS = CycleIndexSeriesRing(QQ) sage: f = CIS([p([]), p([1]), p([2]), p.zero()]) sage: f.stretch(3).coefficients(10) [p[], 0, 0, p[3], 0, 0, p[6], 0, 0, 0] @@ -422,8 +454,9 @@ def _stretch_gen(self, k, ao): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(p) - sage: f = CIS([p([1])]) + sage: CIS = CycleIndexSeriesRing(QQ) + sage: f = CIS([p([1])]) # This is the power series whose all coefficients + ....: # are p[1]. Not combinatorially meaningful! sage: g = f._stretch_gen(2,0) sage: [next(g) for i in range(10)] [p[2], 0, p[2], 0, p[2], 0, p[2], 0, p[2], 0] @@ -564,7 +597,7 @@ def __invert__(self): .. [BLL] F. Bergeron, G. Labelle, and P. Leroux. "Combinatorial species and tree-like structures". - Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. + Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. .. [BLL-Intro] Francois Bergeron, Gilbert Labelle, and Pierre Leroux. "Introduction to the Theory of Species of Structures", March 14, 2008. http://bergeron.math.uqam.ca/Site/bergeron_anglais_files/livre_combinatoire.pdf From 3b04193e8ec002779f22d6ae14e0f588a82a5a5e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 10 Feb 2015 18:14:57 +0100 Subject: [PATCH 087/665] oops --- src/sage/combinat/species/generating_series.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index f2c46150881..01e3dd90701 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -330,8 +330,6 @@ def CycleIndexSeriesRing(R): Note that is is just a :class:`LazyPowerSeriesRing` (whose base ring is `\Lambda`) whose elements have some extra methods. - The - EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing From 5ef441aeca37ec354b0a6a8b423583add44395b1 Mon Sep 17 00:00:00 2001 From: Jernej Azarija Date: Wed, 11 Feb 2015 13:50:08 +0100 Subject: [PATCH 088/665] Fixed patching of bliss --- build/pkgs/bliss/patches/digraph_heuristic.patch | 4 ++-- build/pkgs/bliss/spkg-install | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/pkgs/bliss/patches/digraph_heuristic.patch b/build/pkgs/bliss/patches/digraph_heuristic.patch index c1b154900bc..6e61458f424 100644 --- a/build/pkgs/bliss/patches/digraph_heuristic.patch +++ b/build/pkgs/bliss/patches/digraph_heuristic.patch @@ -1,5 +1,5 @@ ---- bliss-0.72/graph.cc 2011-05-12 15:29:46.000000000 +0200 -+++ /tmp/bliss-0.72/graph.cc 2015-01-28 13:40:42.289179859 +0100 +--- src/graph.cc 2015-02-11 13:20:39.922021355 +0100 ++++ src-patched/graph_new.cc 2015-02-11 13:20:15.546020960 +0100 @@ -1920,6 +1920,7 @@ Digraph::Digraph(const unsigned int nof_vertices) { diff --git a/build/pkgs/bliss/spkg-install b/build/pkgs/bliss/spkg-install index ab30bacc6bc..e3f9c7cb15a 100755 --- a/build/pkgs/bliss/spkg-install +++ b/build/pkgs/bliss/spkg-install @@ -6,9 +6,9 @@ if [ "$SAGE_LOCAL" = "" ]; then exit 1 fi -cd "src" -for patch in patches/*.patch; do +cd "src" +for patch in ../patches/*.patch; do [ -r "$patch" ] || continue # Skip non-existing or non-readable patches patch -p1 <"$patch" if [ $? -ne 0 ]; then @@ -17,6 +17,7 @@ for patch in patches/*.patch; do fi done + $MAKE && mv libbliss.a "$SAGE_LOCAL/lib" && mv *.hh "$SAGE_LOCAL/include" if [ $? -ne 0 ]; then From a4b4c6ee3ce9f82864e3b179380517ff123582ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 16 Feb 2015 16:51:56 +0100 Subject: [PATCH 089/665] trac #11529 Remove dependency to set factories --- src/sage/combinat/ordered_tree.py | 2 - src/sage/combinat/rooted_tree.py | 297 +++++++++++++++--------------- 2 files changed, 151 insertions(+), 148 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index ebc03b69dcf..dd42dc88327 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -28,7 +28,6 @@ from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family -from sage.misc.cachefunc import cached_method class OrderedTree(AbstractClonableTree, ClonableList): @@ -718,7 +717,6 @@ def _element_constructor_(self, *args, **keywords): Element = OrderedTree - from sage.misc.lazy_attribute import lazy_attribute from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.composition import Compositions diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 5f387823365..e78412cf811 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -7,11 +7,10 @@ """ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_cat import Sets from sage.combinat.ranker import on_fly -from sage.combinat.abstract_tree import ( - AbstractClonableTree, AbstractLabelledClonableTree) +from sage.combinat.abstract_tree import (AbstractClonableTree, + AbstractLabelledClonableTree) from sage.misc.cachefunc import cached_function from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute @@ -24,7 +23,6 @@ from sage.structure.list_clone import NormalizedClonableList from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -import sage.structure.set_factories as factories @cached_function @@ -247,114 +245,74 @@ def graft_on_root(self, other): return resu -class RootedTreesFactory(factories.SetFactory): +class RootedTrees(UniqueRepresentation, Parent): """ Factory class for rooted trees - """ - def __call__(self, n=(), policy=None): + INPUT: + + - ``size`` -- (optional) an integer + + OUPUT: + + - the set of all rooted trees (of the given ``size`` if specified) + + EXAMPLES:: + + sage: RootedTrees() + Rooted trees + + sage: RootedTrees(2) + Rooted trees with 2 nodes + """ + @staticmethod + def __classcall_private__(cls, n=None): """ TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all, RootedTrees_size + sage: from sage.combinat.rooted_tree import (RootedTrees_all, + ....: RootedTrees_size) sage: RootedTrees(2) is RootedTrees_size(2) True sage: RootedTrees(5).cardinality() 9 sage: RootedTrees() is RootedTrees_all() True - """ - if policy is None: - policy = self._default_policy - if n == (): - return RootedTrees_all(policy) - elif isinstance(n, (Integer, int)) and n >= 0: - return RootedTrees_size(n, policy) - msg = "Do not know how to compute {}({})".format(self, n) - raise NotImplementedError(msg) - - # try: - # from sage.combinat.partition import Partition - # lst = Partition(n) - # except ValueError: - # raise NotImplementedError("Don't know how to compute %%(%s)"%( - # self, n)) - # else: - # return RootedTrees_part(lst, policy) - - def add_constraints(self, cons, (n, st)): - """ - EXAMPLES:: - - sage: RootedTrees.add_constraints((), ((3,), {})) - (3,) - sage: RootedTrees.add_constraints((3,), ((), {})) - (3,) - """ - return cons + n - - @lazy_attribute - def _default_policy(self): - r""" TESTS:: - sage: from sage.combinat.rooted_tree import RootedTreesFactory - sage: RT = RootedTreesFactory() - sage: RT._default_policy - Set factory policy for with parent Rooted trees[=Rooted tree set factory(())] - """ - return factories.TopMostParentPolicy(self, (), RootedTree) - - def __repr__(self): - """ - TESTS:: - - sage: from sage.combinat.rooted_tree import RootedTreesFactory - sage: RootedTreesFactory() - Rooted tree set factory + sage: RootedTrees(0) + Traceback (most recent call last): + ... + ValueError: n must be a positive integer """ - return "Rooted tree set factory" - -RootedTrees = RootedTreesFactory() + if n is None: + return RootedTrees_all() + else: + if not (isinstance(n, (Integer, int)) and n >= 1): + raise ValueError("n must be a positive integer") + return RootedTrees_size(Integer(n)) -class RootedTrees_all(factories.ParentWithSetFactory, - DisjointUnionEnumeratedSets): - """ - TESTS:: +class RootedTrees_all(DisjointUnionEnumeratedSets, RootedTrees): - sage: sum(x^len(t) for t in - ... set(RootedTree(t) for t in OrderedTrees(6))) - x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x - sage: sum(x^len(t) for t in RootedTrees(6)) - x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x - """ - @staticmethod - def __classcall_private__(cls, policy=RootedTrees._default_policy): + def __init__(self): """ - Input normalization - TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all - sage: RootedTrees() is RootedTrees_all() - True - """ - return super(RootedTrees_all, cls).__classcall__(cls, policy) + sage: from sage.combinat.rooted_tree import RootedTrees_all - def __init__(self, policy=RootedTrees._default_policy): - """ - TESTS:: + sage: sum(x**len(t) for t in + ....: set(RootedTree(t) for t in OrderedTrees(6))) + x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x + sage: sum(x**len(t) for t in RootedTrees(6)) + x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x sage: TestSuite(RootedTrees()).run() """ - factories.ParentWithSetFactory.__init__(self, (), policy, - category=InfiniteEnumeratedSets()) DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), self._of_size), - facade=True, keepkey=False, - category=self.category()) + self, Family(NonNegativeIntegers(), RootedTrees_size), + facade=True, keepkey=False) def _repr_(self): r""" @@ -365,32 +323,29 @@ def _repr_(self): """ return "Rooted trees" - def _of_size(self, size): - r""" - The sub-enumerated set of trees of a given size - - Passed to :class:DisjointUnionEnumeratedSets - + def __contains__(self, x): + """ TESTS:: - sage: RootedTrees()._of_size(4) - Rooted trees with 4 nodes + sage: S = RootedTrees() + sage: 1 in S + False + sage: S([]) in S + True """ - return RootedTrees_size(size, policy=self.facade_policy()) - - def check_element(self, el, check): - r""" - Check that a given tree actually belongs to ``self`` + return isinstance(x, self.element_class) - See :class:`sage.structure.set_factories.ParentWithSetFactory` + def __call__(self, x=None, *args, **keywords): + """ + Ensure that ``None`` instead of ``0`` is passed by default. TESTS:: - sage: RT = RootedTrees() - sage: RT([[],[]]) # indirect doctest - [[], []] + sage: B = RootedTrees() + sage: B([]) + [] """ - pass + return super(RootedTrees, self).__call__(x, *args, **keywords) def unlabelled_trees(self): """ @@ -424,40 +379,40 @@ def labelled_trees(self): """ return LabelledRootedTrees() + def _element_constructor_(self, *args, **keywords): + """ + EXAMPLES:: -class RootedTrees_size(factories.ParentWithSetFactory, UniqueRepresentation): - """ - The enumerated set of rooted trees with a given number of nodes + sage: B = RootedTrees() + sage: B._element_constructor_([]) + [] + sage: B([[],[]]) # indirect doctest + [[], []] + """ + return self.element_class(self, *args, **keywords) - EXAMPLES:: + Element = RootedTree + +class RootedTrees_size(RootedTrees): """ - @staticmethod - def __classcall_private__(cls, n, policy=RootedTrees._default_policy): - """ - Input normalization + The enumerated set of rooted trees with a given number of nodes - TESTS:: + TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_size - sage: RootedTrees(4) is RootedTrees_size(4) - True - sage: RootedTrees_size(4) is RootedTrees_size(int(4)) - True - """ - return super(RootedTrees_size, cls).__classcall__( - cls, Integer(n), policy) + sage: from sage.combinat.rooted_tree import RootedTrees_size + sage: for i in range(1, 6): TestSuite(RootedTrees_size(i)).run() - def __init__(self, n, policy): + """ + def __init__(self, n): """ TESTS:: - sage: for i in range(0, 6): + sage: for i in range(1, 6): ....: TestSuite(RootedTrees(i)).run() """ + super(RootedTrees_size, self).__init__(category=FiniteEnumeratedSets()) self._n = n - factories.ParentWithSetFactory.__init__(self, (n,), policy, - category=FiniteEnumeratedSets()) def _repr_(self): r""" @@ -468,6 +423,27 @@ def _repr_(self): """ return "Rooted trees with {} nodes".format(self._n) + def __contains__(self, x): + """ + TESTS:: + + sage: S = RootedTrees(3) + sage: 1 in S + False + sage: S([[],[]]) in S + True + """ + return isinstance(x, self.element_class) and x.node_number() == self._n + + def _an_element_(self): + """ + TESTS:: + + sage: RootedTrees(4).an_element() # indirect doctest + [[[[]]]] + """ + return self.first() + def __iter__(self): """ An iterator for ``self`` @@ -475,8 +451,6 @@ def __iter__(self): EXAMPLES:: sage: from sage.combinat.rooted_tree import * - sage: RootedTrees(0).list() - [] sage: RootedTrees(1).list() [[]] sage: RootedTrees(2).list() @@ -484,9 +458,7 @@ def __iter__(self): sage: RootedTrees(3).list() [[[[]]], [[], []]] """ - if self._n == 0: - pass - elif self._n == 1: + if self._n == 1: yield self._element_constructor_([]) else: from sage.combinat.partition import Partitions @@ -496,7 +468,7 @@ def __iter__(self): mults = part.to_exp_dict() choices = [] for p, mp in mults.items(): - lp = self.__class__(p, self.policy()).list() + lp = self.__class__(p).list() new_choice = MultichooseNK(len(lp), mp).map( lambda l: [lp[i] for i in l]).list() choices.append(new_choice) @@ -507,8 +479,6 @@ def check_element(self, el, check=True): r""" Check that a given tree actually belongs to ``self`` - See :class:`sage.structure.set_factories.ParentWithSetFactory` - EXAMPLES:: sage: RT3 = RootedTrees(3) @@ -517,10 +487,10 @@ def check_element(self, el, check=True): sage: RT3([[],[],[]]) # indirect doctest Traceback (most recent call last): ... - ValueError: Wrong number of nodes + ValueError: wrong number of nodes """ if el.node_number() != self._n: - raise ValueError("Wrong number of nodes") + raise ValueError("wrong number of nodes") def cardinality(self): r""" @@ -532,11 +502,56 @@ def cardinality(self): 1 sage: RootedTrees(3).cardinality() 2 - sage: RootedTrees(0).cardinality() - 0 """ return number_of_rooted_trees(self._n) + @lazy_attribute + def _parent_for(self): + """ + The parent of the elements generated by ``self``. + + TESTS:: + + sage: S = RootedTrees(3) + sage: S._parent_for + Rooted trees + """ + return RootedTrees_all() + + @lazy_attribute + def element_class(self): + """ + TESTS:: + + sage: S = RootedTrees(3) + sage: S.element_class + + sage: S.first().__class__ == RootedTrees().first().__class__ + True + """ + return self._parent_for.element_class + + def _element_constructor_(self, *args, **keywords): + """ + EXAMPLES:: + + sage: S = RootedTrees(2) + sage: S([]) # indirect doctest + Traceback (most recent call last): + ... + ValueError: wrong number of nodes + sage: S([[]]) # indirect doctest + [[]] + + sage: S = RootedTrees(1) # indirect doctest + sage: S([]) + [] + """ + res = self.element_class(self._parent_for, *args, **keywords) + if res.node_number() != self._n: + raise ValueError("wrong number of nodes") + return res + class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): """ @@ -680,16 +695,6 @@ def _an_element_(self): t2 = LT([[]], label=5) return LT([t, t1, t2], label="toto") - def _element_constructor_(self, *args, **keywords): - """ - EXAMPLES:: - - sage: T = LabelledRootedTrees() - sage: T([], label=2) # indirect doctest - 2[] - """ - return self.element_class(self, *args, **keywords) - def unlabelled_trees(self): """ Returns the set of unlabelled trees associated to ``self`` From 49681fce17ef8ea7f37872779c759e9ec73a6f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 16 Feb 2015 21:09:00 +0100 Subject: [PATCH 090/665] trac #11529 little more doc and change name of cayley_normalize --- src/sage/combinat/ordered_tree.py | 66 ++++++++++++++++++++----------- src/sage/combinat/rooted_tree.py | 13 +++++- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index dd42dc88327..876aa2bb9e8 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -521,36 +521,58 @@ def left_right_symmetry(self): _cayley_ranker = sage.combinat.ranker.on_fly() @cached_method - def cayley_normalize(self): + def normalize(self, inplace=False): """ - sage: (OrderedTree([[],[[]]]).cayley_normalize() == - ... OrderedTree([[[]],[]]).cayley_normalize()) - True - """ - rank, unrank = self._cayley_ranker - with self.clone() as res: - resl = res._get_list() - for i in range(len(resl)): - resl[i] = resl[i].cayley_normalize() - resl.sort(key = rank) - return unrank(rank(res)) + Return the normalized tree of ``self``. - # TODO !!! - def cayley_normalize_in_place(self): - """ - In place cayley normalization + INPUT: + + - ``inplace`` -- boolean, (default ``False``) if ``True``, + then ``self`` is modified and nothing returned. Otherwise + the normalized tree is returned. + + The normalization has a recursive definition. It means first + that every sub-tree is itself normalized, and also that + sub-trees are sorted. Here the sort is performed according to + the rank function. + + Consider the quotient map that sends a planar rooted tree to + the associated "abstract" rooted tree. This function is a + section of this map. This is used to work with rooted trees. EXAMPLES:: - sage: (OrderedTree([[],[[]]]).cayley_normalize() == - ... OrderedTree([[[]],[]]).cayley_normalize()) + sage: OT = OrderedTree + sage: ta = OT([[],[[]]]) + sage: tb = OT([[[]],[]]) + sage: ta.normalize() == tb.normalize() True + sage: ta == tb + False + + An example with inplace normalization:: + + sage: OT = OrderedTree + sage: ta = OT([[],[[]]]) + sage: tb = OT([[[]],[]]) + sage: ta.normalize(inplace=True); ta + [[], [[]]] + sage: tb.normalize(inplace=True); tb + [[], [[]]] """ rank, unrank = self._cayley_ranker - resl = self._get_list() - for i in range(len(resl)): - resl[i] = resl[i].cayley_normalized() - resl.sort(key = rank) + if not inplace: + with self.clone() as res: + resl = res._get_list() + for i in range(len(resl)): + resl[i] = resl[i].normalize() + resl.sort(key=rank) + return unrank(rank(res)) + else: + resl = self._get_list() + for i in range(len(resl)): + resl[i] = resl[i].normalize() + resl.sort(key=rank) # Abstract class to serve as a Factory no instance are created. diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index e78412cf811..2444d9f20c2 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -143,11 +143,20 @@ def __init__(self, parent=None, children=[], check=True): def normalize(self): r""" - Normalize ``self`` + Normalize ``self``. There should be no need to call ``normalize`` directly as it is called automatically upon creation and cloning or - modification. + modification (by ``NormalizedClonableList``). + + The normalization has a recursive definition. It means first + that every sub-tree is itself normalized, and also that + sub-trees are sorted. Here the sort is performed according to + the rank function. + + Consider the quotient map that sends a planar rooted tree to + the associated "abstract" rooted tree. This function is a + section of this map. This is used to work with rooted trees. EXAMPLES:: From b8f8004bae8ebff79b313c571a64c81aba89281a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 16 Feb 2015 21:15:00 +0100 Subject: [PATCH 091/665] trac #11529 remove the word Cayley as asked --- src/sage/combinat/rooted_tree.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 2444d9f20c2..5417375ee39 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -1,5 +1,5 @@ r""" -Rooted (Cayley, Unordered) Trees +Rooted (Unordered) Trees AUTHORS: @@ -72,6 +72,14 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): [[], [[]]] sage: RootedTree([[[]], []]) [[], [[]]] + + One can also enter a rooted tree by using a simple numerical + encoding of rooted trees:: + + sage: from sage.combinat.abstract_tree import from_hexacode + sage: RT = RootedTrees() + sage: from_hexacode('31010200', RT) + [[[]], [[]], [[], []]] """ # Standard auto-parent trick __metaclass__ = ClasscallMetaclass From 76f695772807e9cad8d48a6fb0fc14e78289a2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 16 Feb 2015 22:18:01 +0100 Subject: [PATCH 092/665] trac #11529 inclusion of doc into table of contents, etc --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/enumerated_sets.py | 1 + src/sage/combinat/rooted_tree.py | 44 +++++++++---------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index d9be071e7e5..1f60c5d1046 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -233,6 +233,7 @@ Comprehensive Module list sage/combinat/root_system/weight_space sage/combinat/root_system/weyl_characters sage/combinat/root_system/weyl_group + sage/combinat/rooted_tree sage/combinat/rsk sage/combinat/schubert_polynomial sage/combinat/set_partition diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index 16d24e01253..a66f31abda8 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -97,6 +97,7 @@ - :ref:`sage.combinat.abstract_tree` - :ref:`sage.combinat.ordered_tree` - :ref:`sage.combinat.binary_tree` +- :ref:`sage.combinat.rooted_tree` Enumerated sets related to graphs --------------------------------- diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 5417375ee39..8fa0e10b076 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -27,15 +27,15 @@ @cached_function def number_of_rooted_trees(n): - """ - Number of rooted trees with `n` nodes + r""" + Return the number of rooted trees with `n` nodes. Compute the number `a(n)` of rooted trees with `n` nodes using the recursive formula ([SL000081]_): .. math:: - a(n+1) = (1/n) * sum_{k=1..n} ( sum_{d|k} d*a(d) ) * a(n-k+1) + a(n+1) = 1/n \sum_{k=1}^{n} ( \sum_{d|k} d a(d) ) a(n-k+1) EXAMPLES:: @@ -78,7 +78,7 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): sage: from sage.combinat.abstract_tree import from_hexacode sage: RT = RootedTrees() - sage: from_hexacode('31010200', RT) + sage: from_hexacode('32001010', RT) [[[]], [[]], [[], []]] """ # Standard auto-parent trick @@ -192,7 +192,7 @@ def normalize(self): def is_empty(self): r""" - Return if ``self`` is the empty tree + Return if ``self`` is the empty tree. For rooted trees, returns always ``False`` @@ -213,7 +213,7 @@ def is_empty(self): def graft_list(self, other): """ - Return the list of trees obtained by grafting ``other`` on ``self`` + Return the list of trees obtained by grafting ``other`` on ``self``. This is useful for free pre-Lie algebras. @@ -240,7 +240,7 @@ def graft_list(self, other): def graft_on_root(self, other): """ - Return the tree obtained by grafting ``other`` on the root of ``self`` + Return the tree obtained by grafting ``other`` on the root of ``self``. This is useful for free Nap algebras. @@ -366,7 +366,7 @@ def __call__(self, x=None, *args, **keywords): def unlabelled_trees(self): """ - Returns the set of unlabelled trees associated to ``self`` + Return the set of unlabelled trees associated to ``self``. EXAMPLES:: @@ -377,7 +377,7 @@ def unlabelled_trees(self): def labelled_trees(self): """ - Returns the set of labelled trees associated to ``self`` + Return the set of labelled trees associated to ``self``. EXAMPLES:: @@ -494,7 +494,7 @@ def __iter__(self): def check_element(self, el, check=True): r""" - Check that a given tree actually belongs to ``self`` + Check that a given tree actually belongs to ``self``. EXAMPLES:: @@ -511,7 +511,7 @@ def check_element(self, el, check=True): def cardinality(self): r""" - Return the cardinality of ``self`` + Return the cardinality of ``self``. EXAMPLES:: @@ -574,13 +574,13 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): """ Labelled rooted trees - A labelled rooted tree is a rooted tree with a label attached at each node + A labelled rooted tree is a rooted tree with a label attached at each node. INPUT: - ``children`` -- a list or tuple or more generally any iterable - of trees or object convertible to trees - - ``label`` -- any Sage object default to ``None`` + of trees or object convertible to trees + - ``label`` -- any Sage object (default is ``None``) EXAMPLES:: @@ -593,13 +593,13 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): sage: LabelledRootedTree([[],[[], []]], label = 3) 3[None[], None[None[], None[]]] - Children are reordered in a session dependant order: + Children are reordered in a session dependant order:: sage: y = LabelledRootedTree([], label = 5); x 3[] - sage: xyy2 = LabelledRootedTree((x, y, y), label = 2); xyy2 #random + sage: xyy2 = LabelledRootedTree((x, y, y), label = 2); xyy2 #random 2[3[], 5[], 5[]] - sage: yxy2 = LabelledRootedTree((y, x, y), label = 2); yxy2 #random + sage: yxy2 = LabelledRootedTree((y, x, y), label = 2); yxy2 #random 2[3[], 5[], 5[]] sage: xyy2 == yxy2 True @@ -652,7 +652,7 @@ def _auto_parent(cls): class LabelledRootedTrees(UniqueRepresentation, Parent): """ This is a parent stub to serve as a factory class for trees with various - labels constraints + labels constraints. EXAMPLES:: @@ -688,7 +688,7 @@ def _repr_(self): def cardinality(self): """ - Returns the cardinality of `self` + Return the cardinality of ``self``. EXAMPLE:: @@ -699,7 +699,7 @@ def cardinality(self): def _an_element_(self): """ - Returns a labelled tree + Return a labelled tree. EXAMPLE:: @@ -714,7 +714,7 @@ def _an_element_(self): def unlabelled_trees(self): """ - Returns the set of unlabelled trees associated to ``self`` + Return the set of unlabelled trees associated to ``self``. EXAMPLES:: @@ -725,7 +725,7 @@ def unlabelled_trees(self): def labelled_trees(self): """ - Returns the set of labelled trees associated to ``self`` + Return the set of labelled trees associated to ``self``. EXAMPLES:: From ac7687a92a4b288aa58ba140515da7f1e5f357b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 17 Feb 2015 14:39:18 +0100 Subject: [PATCH 093/665] trac #11529 a few changes in the doc --- src/sage/combinat/ordered_tree.py | 12 ++++---- src/sage/combinat/rooted_tree.py | 46 +++++++++++++++++-------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 876aa2bb9e8..c52c8a9aa68 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -518,11 +518,11 @@ def left_right_symmetry(self): return OrderedTree(children) import sage.combinat.ranker - _cayley_ranker = sage.combinat.ranker.on_fly() + _unordered_ranker = sage.combinat.ranker.on_fly() @cached_method def normalize(self, inplace=False): - """ + r""" Return the normalized tree of ``self``. INPUT: @@ -536,9 +536,9 @@ def normalize(self, inplace=False): sub-trees are sorted. Here the sort is performed according to the rank function. - Consider the quotient map that sends a planar rooted tree to - the associated "abstract" rooted tree. This function is a - section of this map. This is used to work with rooted trees. + Consider the quotient map `\pi` that sends a planar rooted tree to + the associated "abstract" rooted tree. This function computes the + composite `s \circ \pi`, where `s` is a section of `\pi`. EXAMPLES:: @@ -560,7 +560,7 @@ def normalize(self, inplace=False): sage: tb.normalize(inplace=True); tb [[], [[]]] """ - rank, unrank = self._cayley_ranker + rank, unrank = self._unordered_ranker if not inplace: with self.clone() as res: resl = res._get_list() diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 8fa0e10b076..5d4df049b48 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -5,7 +5,6 @@ - Florent Hivert (2011): initial revision """ - from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets from sage.combinat.ranker import on_fly @@ -147,12 +146,17 @@ def __init__(self, parent=None, children=[], check=True): children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) - _cayley_ranker = on_fly() + _unordered_ranker = on_fly() def normalize(self): r""" Normalize ``self``. + This function is at the core of the implementation of rooted + (unordered) trees. The underlying structure is provided by + ordered rooted trees. Every rooted tree is represented by a + normalized element in the set of its planar embeddings. + There should be no need to call ``normalize`` directly as it is called automatically upon creation and cloning or modification (by ``NormalizedClonableList``). @@ -162,10 +166,6 @@ def normalize(self): sub-trees are sorted. Here the sort is performed according to the rank function. - Consider the quotient map that sends a planar rooted tree to - the associated "abstract" rooted tree. This function is a - section of this map. This is used to work with rooted trees. - EXAMPLES:: sage: RT = RootedTree @@ -178,7 +178,7 @@ def normalize(self): sage: rt1._get_list() is rt2._get_list() True """ - rank, unrank = self._cayley_ranker + rank, unrank = self._unordered_ranker self._require_mutable() for st in self: assert st.is_immutable(), "Subtree {} is not normalized".format(st) @@ -352,17 +352,17 @@ def __contains__(self, x): """ return isinstance(x, self.element_class) - def __call__(self, x=None, *args, **keywords): - """ - Ensure that ``None`` instead of ``0`` is passed by default. + # def __call__(self, x=[], *args, **keywords): + # """ + # Ensure that ``[]`` is passed by default. - TESTS:: + # TESTS:: - sage: B = RootedTrees() - sage: B([]) - [] - """ - return super(RootedTrees, self).__call__(x, *args, **keywords) + # sage: B = RootedTrees() + # sage: B() + # [] + # """ + # return super(RootedTrees, self).__call__(x, *args, **keywords) def unlabelled_trees(self): """ @@ -580,6 +580,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): - ``children`` -- a list or tuple or more generally any iterable of trees or object convertible to trees + - ``label`` -- any Sage object (default is ``None``) EXAMPLES:: @@ -651,8 +652,7 @@ def _auto_parent(cls): class LabelledRootedTrees(UniqueRepresentation, Parent): """ - This is a parent stub to serve as a factory class for trees with various - labels constraints. + This is a parent stub to serve as a factory class for labelled rooted trees EXAMPLES:: @@ -666,6 +666,10 @@ class LabelledRootedTrees(UniqueRepresentation, Parent): 2[3[], 3[], 3[]] sage: y.parent() is LRT True + + .. TODO:: + + add the possibility to restrict the labels to a fixed set. """ def __init__(self, category=None): """ @@ -679,6 +683,8 @@ def __init__(self, category=None): def _repr_(self): """ + Return the string representation of ``self``. + TESTS:: sage: LabelledRootedTrees() # indirect doctest @@ -704,13 +710,13 @@ def _an_element_(self): EXAMPLE:: sage: LabelledRootedTrees().an_element() # indirect doctest - toto[3[], 42[3[], 3[]], 5[None[]]] + alpha[3[], 42[3[], 3[]], 5[None[]]] """ LT = self._element_constructor_ t = LT([], label=3) t1 = LT([t, t], label=42) t2 = LT([[]], label=5) - return LT([t, t1, t2], label="toto") + return LT([t, t1, t2], label="alpha") def unlabelled_trees(self): """ From 3e619b011df83fe7782a2b31c35354f1dd4dfda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 17 Feb 2015 15:12:06 +0100 Subject: [PATCH 094/665] trac #11529 more doc again --- src/sage/combinat/rooted_tree.py | 47 ++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 5d4df049b48..097e4a083c1 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -135,14 +135,24 @@ def __init__(self, parent=None, children=[], check=True): """ TESTS:: - sage: t1 = RootedTrees(4)([[],[[]]]) + sage: RT4 = RootedTrees(4) + sage: t1 = RT4([[],[[]]]) sage: TestSuite(t1).run() + + Some bad inputs are refused:: + + sage: RT4(69) + Traceback (most recent call last): + ... + TypeError: input (69) is not a valid tree """ + try: + children = list(children) + except TypeError: + raise TypeError("input ({}) is not a valid tree".format(children)) tst = (children.__class__ is self.__class__ and children.parent() == parent) - if tst: - children = list(children) - else: + if not tst: children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) @@ -215,6 +225,11 @@ def graft_list(self, other): """ Return the list of trees obtained by grafting ``other`` on ``self``. + Here grafting means that one takes the disjoint union of + ``self`` and ``other``, and add one edge from the root of + other to a vertex of ``self``. The root of the resulting + tree is the root of ``self``. + This is useful for free pre-Lie algebras. EXAMPLES:: @@ -242,6 +257,11 @@ def graft_on_root(self, other): """ Return the tree obtained by grafting ``other`` on the root of ``self``. + Here grafting means that one takes the disjoint union of + ``self`` and ``other``, and add one edge from the root of + other to the root of ``self``. The root of the resulting + tree is the root of ``self``. + This is useful for free Nap algebras. EXAMPLES:: @@ -352,18 +372,6 @@ def __contains__(self, x): """ return isinstance(x, self.element_class) - # def __call__(self, x=[], *args, **keywords): - # """ - # Ensure that ``[]`` is passed by default. - - # TESTS:: - - # sage: B = RootedTrees() - # sage: B() - # [] - # """ - # return super(RootedTrees, self).__call__(x, *args, **keywords) - def unlabelled_trees(self): """ Return the set of unlabelled trees associated to ``self``. @@ -419,7 +427,6 @@ class RootedTrees_size(RootedTrees): sage: from sage.combinat.rooted_tree import RootedTrees_size sage: for i in range(1, 6): TestSuite(RootedTrees_size(i)).run() - """ def __init__(self, n): """ @@ -465,6 +472,10 @@ def __iter__(self): """ An iterator for ``self`` + This generates the rooted trees of given size. The algorithm + first picks a partition for the sizes of subtrees, then picks + appropriate tuples of smaller trees. + EXAMPLES:: sage: from sage.combinat.rooted_tree import * @@ -496,6 +507,8 @@ def check_element(self, el, check=True): r""" Check that a given tree actually belongs to ``self``. + This just checks the number of vertices. + EXAMPLES:: sage: RT3 = RootedTrees(3) From 5219d2e4ef7c38fe5ce7a40289cdc118cac2bff3 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 17 Feb 2015 16:03:40 -0500 Subject: [PATCH 095/665] deterministic normalization of rooted ordered trees --- src/sage/combinat/ordered_tree.py | 70 ++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index c52c8a9aa68..32ce12bed97 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -517,8 +517,63 @@ def left_right_symmetry(self): children.reverse() return OrderedTree(children) - import sage.combinat.ranker - _unordered_ranker = sage.combinat.ranker.on_fly() + def dendrog_cmp(self, other): + r""" + Return `-1` if ``self`` is smaller than ``other`` in the + dendrographical order; return `0` if they are equal; + return `1` if ``other`` is smaller. + + The dendrographical order is a total order on the set of + ordered rooted trees; it is defined recursively as + follows: An ordered rooted tree `T` with children + `T_1, T_2, \ldots, T_a` is smaller than an + ordered rooted tree `S` with children + `S_1, S_2, \ldots, S_b` if either `a < b` or (`a = b` + and there exists a `1 \leq i \leq a` such that + `T_1 = S_1, T_2 = S_2, \ldots, T_{i-1} = S_{i-1}` and + `T_i < S_i`. + + INPUT: + + - ``other``: an ordered binary tree. + + OUTPUT: + + `-1`, if ``smaller < other`` with respect to the + dendrographical order. + `0`, if ``smaller == other``. + `1`, if ``smaller > other`` with respect to the + dendrographical order. + + EXAMPLES:: + + sage: OT = OrderedTree + sage: ta = OT([]) + sage: tb = OT([[], [], [[], []]]) + sage: tc = OT([[], [[], []], []]) + sage: td = OT([[[], []], [], []]) + sage: te = OT([[], []]) + sage: tf = OT([[], [], []]) + sage: tg = OT([[[], []], [[], []]]) + sage: l = [ta, tb, tc, td, te, tf, tg] + sage: [l[i].dendrog_cmp(l[j]) for i in range(7) for j in range(7)] + [0, -1, -1, -1, -1, -1, -1, + 1, 0, -1, -1, 1, 1, 1, + 1, 1, 0, -1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, + 1, -1, -1, -1, 0, -1, -1, + 1, -1, -1, -1, 1, 0, 1, + 1, -1, -1, -1, 1, -1, 0] + """ + if len(self) < len(other): + return -1 + if len(self) > len(other): + return 1 + for (a, b) in zip(self, other): + comp = a.dendrog_cmp(b) + if comp != 0: + return comp + return 0 @cached_method def normalize(self, inplace=False): @@ -549,6 +604,8 @@ def normalize(self, inplace=False): True sage: ta == tb False + sage: ta.normalize() + [[], [[]]] An example with inplace normalization:: @@ -560,19 +617,20 @@ def normalize(self, inplace=False): sage: tb.normalize(inplace=True); tb [[], [[]]] """ - rank, unrank = self._unordered_ranker + def dendrog_cmp(a, b): + return a.dendrog_cmp(b) if not inplace: with self.clone() as res: resl = res._get_list() for i in range(len(resl)): resl[i] = resl[i].normalize() - resl.sort(key=rank) - return unrank(rank(res)) + resl.sort(cmp=dendrog_cmp) + return res else: resl = self._get_list() for i in range(len(resl)): resl[i] = resl[i].normalize() - resl.sort(key=rank) + resl.sort(cmp=dendrog_cmp) # Abstract class to serve as a Factory no instance are created. From c1aca706fd40900e59024f19a4e29fe190fd65f2 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 18 Feb 2015 16:53:40 +0100 Subject: [PATCH 096/665] reverting changes, keeping dendrographical order --- src/sage/combinat/ordered_tree.py | 105 ++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 32ce12bed97..7a97aa5635b 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -517,6 +517,63 @@ def left_right_symmetry(self): children.reverse() return OrderedTree(children) + import sage.combinat.ranker + _unordered_ranker = sage.combinat.ranker.on_fly() + + @cached_method + def normalize(self, inplace=False): + r""" + Return the normalized tree of ``self``. + + INPUT: + + - ``inplace`` -- boolean, (default ``False``) if ``True``, + then ``self`` is modified and nothing returned. Otherwise + the normalized tree is returned. + + The normalization has a recursive definition. It means first + that every sub-tree is itself normalized, and also that + sub-trees are sorted. Here the sort is performed according to + the rank function. + + Consider the quotient map `\pi` that sends a planar rooted tree to + the associated "abstract" rooted tree. This function computes the + composite `s \circ \pi`, where `s` is a section of `\pi`. + + EXAMPLES:: + + sage: OT = OrderedTree + sage: ta = OT([[],[[]]]) + sage: tb = OT([[[]],[]]) + sage: ta.normalize() == tb.normalize() + True + sage: ta == tb + False + + An example with inplace normalization:: + + sage: OT = OrderedTree + sage: ta = OT([[],[[]]]) + sage: tb = OT([[[]],[]]) + sage: ta.normalize(inplace=True); ta + [[], [[]]] + sage: tb.normalize(inplace=True); tb + [[], [[]]] + """ + rank, unrank = self._unordered_ranker + if not inplace: + with self.clone() as res: + resl = res._get_list() + for i in range(len(resl)): + resl[i] = resl[i].normalize() + resl.sort(key=rank) + return unrank(rank(res)) + else: + resl = self._get_list() + for i in range(len(resl)): + resl[i] = resl[i].normalize() + resl.sort(key=rank) + def dendrog_cmp(self, other): r""" Return `-1` if ``self`` is smaller than ``other`` in the @@ -524,8 +581,8 @@ def dendrog_cmp(self, other): return `1` if ``other`` is smaller. The dendrographical order is a total order on the set of - ordered rooted trees; it is defined recursively as - follows: An ordered rooted tree `T` with children + unlabelled ordered rooted trees; it is defined recursively + as follows: An ordered rooted tree `T` with children `T_1, T_2, \ldots, T_a` is smaller than an ordered rooted tree `S` with children `S_1, S_2, \ldots, S_b` if either `a < b` or (`a = b` @@ -535,16 +592,22 @@ def dendrog_cmp(self, other): INPUT: - - ``other``: an ordered binary tree. + - ``other``: an ordered rooted tree. OUTPUT: `-1`, if ``smaller < other`` with respect to the dendrographical order. - `0`, if ``smaller == other``. + `0`, if ``smaller == other`` (as unlabelled ordered + rooted trees). `1`, if ``smaller > other`` with respect to the dendrographical order. + .. NOTE:: + + It is possible to provide labelled trees to this + method; however, their labels are ignored. + EXAMPLES:: sage: OT = OrderedTree @@ -576,9 +639,10 @@ def dendrog_cmp(self, other): return 0 @cached_method - def normalize(self, inplace=False): + def dendrog_normalize(self, inplace=False): r""" - Return the normalized tree of ``self``. + Return the normalized tree of the *unlabelled* ordered rooted + tree ``self`` with respect to the dendrographical order. INPUT: @@ -586,25 +650,28 @@ def normalize(self, inplace=False): then ``self`` is modified and nothing returned. Otherwise the normalized tree is returned. - The normalization has a recursive definition. It means first - that every sub-tree is itself normalized, and also that - sub-trees are sorted. Here the sort is performed according to - the rank function. + The normalized tree of an unlabelled ordered rooted tree + `T` is an unlabelled ordered rooted tree defined recursively + as follows: We first replace all children of `T` by their + normalized trees; then, we reorder these children in weakly + increasing order with respect to the dendrographical order + (:meth:`dendrog_cmp`). - Consider the quotient map `\pi` that sends a planar rooted tree to - the associated "abstract" rooted tree. This function computes the - composite `s \circ \pi`, where `s` is a section of `\pi`. + This can be viewed as an alternative to :meth:`dendrog` for + the case of unlabelled ordered rooted trees. It has the + advantage of giving path-independent results, which can be + used for doctesting output. EXAMPLES:: sage: OT = OrderedTree sage: ta = OT([[],[[]]]) sage: tb = OT([[[]],[]]) - sage: ta.normalize() == tb.normalize() + sage: ta.dendrog_normalize() == tb.dendrog_normalize() True sage: ta == tb False - sage: ta.normalize() + sage: ta.dendrog_normalize() [[], [[]]] An example with inplace normalization:: @@ -612,9 +679,9 @@ def normalize(self, inplace=False): sage: OT = OrderedTree sage: ta = OT([[],[[]]]) sage: tb = OT([[[]],[]]) - sage: ta.normalize(inplace=True); ta + sage: ta.dendrog_normalize(inplace=True); ta [[], [[]]] - sage: tb.normalize(inplace=True); tb + sage: tb.dendrog_normalize(inplace=True); tb [[], [[]]] """ def dendrog_cmp(a, b): @@ -623,13 +690,13 @@ def dendrog_cmp(a, b): with self.clone() as res: resl = res._get_list() for i in range(len(resl)): - resl[i] = resl[i].normalize() + resl[i] = resl[i].dendrog_normalize() resl.sort(cmp=dendrog_cmp) return res else: resl = self._get_list() for i in range(len(resl)): - resl[i] = resl[i].normalize() + resl[i] = resl[i].dendrog_normalize() resl.sort(cmp=dendrog_cmp) From 39a4e1797854ced1cb2dc35d2a1ab43087d9076f Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 19 Feb 2015 14:56:19 -0500 Subject: [PATCH 097/665] disambiguating the notions of trees involved --- src/sage/combinat/rooted_tree.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 097e4a083c1..37eb6a33e52 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -58,7 +58,16 @@ def number_of_rooted_trees(n): class RootedTree(AbstractClonableTree, NormalizedClonableList): r""" - The class for unordered rooted trees + The class for unordered rooted trees. + + The *unordered rooted trees* are an inductive datatype defined + as follows: An unordered rooted tree is either a leaf + (carrying no information), or a multiset of unordered rooted + trees. In the latter case, the trees that belong to this + multiset are said to be the *children* of the tree. + + The *labelled rooted trees* (:class:`LabelledRootedTree`) + form a subclass of this class. One can create a tree from any list (or more generally iterable) of trees or objects convertible to a tree. @@ -585,14 +594,25 @@ def _element_constructor_(self, *args, **keywords): class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): """ - Labelled rooted trees + Labelled rooted trees. + + A labelled rooted tree is a rooted tree with a label + attached at each node. - A labelled rooted tree is a rooted tree with a label attached at each node. + More formally: + The *labelled rooted trees* are an inductive datatype defined + as follows: A labelled rooted tree is either a leaf endowed + with a label (which can be any object, including ``None``), + or a multiset of labelled rooted trees, again endowed with a + label (which may and may not be of the same type as the labels + of the trees from the multiset). In the latter case, the trees + that belong to this multiset are said to be the *children* of + the tree. INPUT: - ``children`` -- a list or tuple or more generally any iterable - of trees or object convertible to trees + of trees or objects convertible to trees - ``label`` -- any Sage object (default is ``None``) From 44d4e924423f122e9c485bc93d292e63fa098d7b Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 19 Feb 2015 16:57:23 -0500 Subject: [PATCH 098/665] abstract base class of LabelledRootedTrees separated from actual _all class; ordered_tree.py reviewed --- src/sage/combinat/ordered_tree.py | 38 ++++++++++++++++++++++--------- src/sage/combinat/rooted_tree.py | 25 ++++++++++++++------ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 7a97aa5635b..4431e5a3527 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -531,13 +531,27 @@ def normalize(self, inplace=False): then ``self`` is modified and nothing returned. Otherwise the normalized tree is returned. - The normalization has a recursive definition. It means first - that every sub-tree is itself normalized, and also that - sub-trees are sorted. Here the sort is performed according to - the rank function. + The normalization of an ordered tree `t` is an ordered tree `s` + which has the property that `t` and `s` are isomorphic as + *unordered* rooted trees, and that if two ordered trees `t` and + `t'` are isomorphic as *unordered* rooted trees, then the + normalizations of `t` and `t'` are identical. In other words, + normalization is a map from the set of ordered trees to itself + which picks a representative from every equivalence class with + respect to the relation of "being isomorphic as unordered + trees", and maps every ordered tree to the representative + chosen from its class. This map is non-deterministically + constructed based on the choices of the user. (More + specifically, it proceeds recursively by first normalizing + every subtree, and then sorting the subtrees. Here the sort is + performed according to the rank function which is constructed + "on the fly", basically sorting the trees in the order in which + they have been first encountered in the given Sage session. + See :meth:`dendrog_normalize` for a deterministic alternative + that works for unlabelled trees.) Consider the quotient map `\pi` that sends a planar rooted tree to - the associated "abstract" rooted tree. This function computes the + the associated unordered rooted tree. Normalization is the composite `s \circ \pi`, where `s` is a section of `\pi`. EXAMPLES:: @@ -588,7 +602,7 @@ def dendrog_cmp(self, other): `S_1, S_2, \ldots, S_b` if either `a < b` or (`a = b` and there exists a `1 \leq i \leq a` such that `T_1 = S_1, T_2 = S_2, \ldots, T_{i-1} = S_{i-1}` and - `T_i < S_i`. + `T_i < S_i`). INPUT: @@ -651,14 +665,16 @@ def dendrog_normalize(self, inplace=False): the normalized tree is returned. The normalized tree of an unlabelled ordered rooted tree - `T` is an unlabelled ordered rooted tree defined recursively - as follows: We first replace all children of `T` by their - normalized trees; then, we reorder these children in weakly + `t` with respect to the dendrographical order is an + unlabelled ordered rooted tree defined recursively + as follows: We first replace all children of `t` by their + normalized trees (with respect to the dendrographical + order); then, we reorder these children in weakly increasing order with respect to the dendrographical order (:meth:`dendrog_cmp`). - This can be viewed as an alternative to :meth:`dendrog` for - the case of unlabelled ordered rooted trees. It has the + This can be viewed as an alternative to :meth:`normalize` + for the case of unlabelled ordered rooted trees. It has the advantage of giving path-independent results, which can be used for doctesting output. diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 37eb6a33e52..914d2562346 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -287,8 +287,7 @@ def graft_on_root(self, other): """ with self.clone() as t: t.append(other) - resu = t - return resu + return t class RootedTrees(UniqueRepresentation, Parent): @@ -346,7 +345,7 @@ def __init__(self): """ TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all + sage: from sage.combinat.rooted_tree import RootedTrees_all sage: sum(x**len(t) for t in ....: set(RootedTree(t) for t in OrderedTrees(6))) @@ -407,7 +406,7 @@ def labelled_trees(self): sage: lb 1[2[], 3[4[], 5[]]] sage: lb.__class__ - + sage: lb.parent() Labelled rooted trees """ @@ -614,7 +613,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): - ``children`` -- a list or tuple or more generally any iterable of trees or objects convertible to trees - - ``label`` -- any Sage object (default is ``None``) + - ``label`` -- any hashable Sage object (default is ``None``) EXAMPLES:: @@ -627,7 +626,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): sage: LabelledRootedTree([[],[[], []]], label = 3) 3[None[], None[None[], None[]]] - Children are reordered in a session dependant order:: + Children are reordered in a session dependent order:: sage: y = LabelledRootedTree([], label = 5); x 3[] @@ -659,7 +658,7 @@ def __classcall_private__(cls, *args, **opts): sage: t0.parent() Labelled rooted trees sage: type(t0) - + """ return cls._auto_parent.element_class(cls._auto_parent, *args, **opts) @@ -704,6 +703,18 @@ class LabelledRootedTrees(UniqueRepresentation, Parent): add the possibility to restrict the labels to a fixed set. """ + @staticmethod + def __classcall_private__(cls, n=None): + """ + TESTS:: + + sage: from sage.combinat.rooted_tree import LabelledRootedTrees_all + sage: LabelledRootedTrees_all() == LabelledRootedTrees() + True + """ + return LabelledRootedTrees_all() + +class LabelledRootedTrees_all(LabelledRootedTrees): def __init__(self, category=None): """ TESTS:: From ac12f31827a5073a4f03fe6cc4db8e7714e51603 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 19 Feb 2015 17:15:42 -0500 Subject: [PATCH 099/665] more edits --- src/sage/combinat/rooted_tree.py | 65 ++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 914d2562346..cf95492a0b2 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -61,13 +61,13 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): The class for unordered rooted trees. The *unordered rooted trees* are an inductive datatype defined - as follows: An unordered rooted tree is either a leaf - (carrying no information), or a multiset of unordered rooted - trees. In the latter case, the trees that belong to this - multiset are said to be the *children* of the tree. + as follows: An unordered rooted tree is a multiset of + unordered rooted trees. The trees that belong to this + multiset are said to be the *children* of the tree. The tree + that has no children is called a *leaf*. The *labelled rooted trees* (:class:`LabelledRootedTree`) - form a subclass of this class. + form a subclass of this class; they carry additional data. One can create a tree from any list (or more generally iterable) of trees or objects convertible to a tree. @@ -80,9 +80,18 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): [[], [[]]] sage: RootedTree([[[]], []]) [[], [[]]] + sage: O = OrderedTree([[[]], []]); O + [[[]], []] + sage: RootedTree(O) # this is O with the ordering forgotten + [[], [[]]] - One can also enter a rooted tree by using a simple numerical - encoding of rooted trees:: + One can also enter any small rooted tree ("small" meaning that + no vertex has more than `15` children) by using a simple + numerical encoding of rooted trees, namely, the + :func:`~sage.combinat.abstract_tree.from_hexacode` function. + (This function actually parametrizes ordered trees, and here + we make it parametrize unordered trees by forgetting the + ordering.) :: sage: from sage.combinat.abstract_tree import from_hexacode sage: RT = RootedTrees() @@ -96,13 +105,16 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): def __classcall_private__(cls, *args, **opts): """ Ensure that rooted trees created by the enumerated sets and directly - are the same and that they are instances of :class:`RootedTree` + are the same and that they are instances of :class:`RootedTree`. TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all + sage: from sage.combinat.rooted_tree import (RootedTrees_all, + ....: RootedTrees_size) sage: issubclass(RootedTrees_all().element_class, RootedTree) True + sage: issubclass(RootedTrees_size(3).element_class, RootedTree) + True sage: t0 = RootedTree([[],[[]]]) sage: t0.parent() Rooted trees @@ -126,7 +138,7 @@ def __classcall_private__(cls, *args, **opts): @lazy_class_attribute def _auto_parent(cls): """ - The automatic parent of the elements of this class + The automatic parent of the elements of this class. When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. @@ -137,7 +149,7 @@ def _auto_parent(cls): Rooted trees sage: RootedTree([]).parent() Rooted trees - """ + """ return RootedTrees_all() def __init__(self, parent=None, children=[], check=True): @@ -429,7 +441,11 @@ def _element_constructor_(self, *args, **keywords): class RootedTrees_size(RootedTrees): """ - The enumerated set of rooted trees with a given number of nodes + The enumerated set of rooted trees with a given number of nodes. + + The number of nodes of a rooted tree is defined recursively: + The number of nodes of a rooted tree with `a` children is `a` + plus the sum of the number of nodes of each of these children. TESTS:: @@ -600,13 +616,18 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): More formally: The *labelled rooted trees* are an inductive datatype defined - as follows: A labelled rooted tree is either a leaf endowed - with a label (which can be any object, including ``None``), - or a multiset of labelled rooted trees, again endowed with a - label (which may and may not be of the same type as the labels - of the trees from the multiset). In the latter case, the trees - that belong to this multiset are said to be the *children* of - the tree. + as follows: A labelled rooted tree is a multiset of labelled + rooted trees, endowed with a label (which can be any object, + including ``None``). The trees that belong to this multiset + are said to be the *children* of the tree. (Notice that the + labels of these children may and may not be of the same type + as the label of the tree). A labelled rooted tree which has + no children (so the only information it carries is its label) + is said to be a *leaf*. + + Every labelled rooted tree gives rise to an unlabelled rooted + tree (:class:`RootedTree`) by forgetting the labels. (This is + implemented as a conversion.) INPUT: @@ -637,6 +658,12 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): sage: xyy2 == yxy2 True + Converting labelled into unlabelled rooted trees by + forgetting the labels: + + sage: RootedTree(yxy2) + [[], [], []] + TESTS:: sage: xyy2._get_list() is yxy2._get_list() From 1c3bfeab259395574fd0fdc3c4653415600448fc Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Thu, 19 Feb 2015 17:20:32 -0500 Subject: [PATCH 100/665] another doctest --- src/sage/combinat/rooted_tree.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index cf95492a0b2..e376763fcb3 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -659,10 +659,13 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): True Converting labelled into unlabelled rooted trees by - forgetting the labels: + forgetting the labels, and back (the labels are + initialized as ``None``):: - sage: RootedTree(yxy2) + sage: yxy2crude = RootedTree(yxy2); yxy2crude [[], [], []] + sage: LabelledRootedTree(yxy2crude) + None[None[], None[], None[]] TESTS:: From ce230e2caa809deb6ac90ece8ce6e3717848827b Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 20 Feb 2015 07:13:53 +0100 Subject: [PATCH 101/665] further edits --- src/sage/combinat/rooted_tree.py | 83 ++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index e376763fcb3..da99a67e048 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -195,7 +195,9 @@ def normalize(self): The normalization has a recursive definition. It means first that every sub-tree is itself normalized, and also that sub-trees are sorted. Here the sort is performed according to - the rank function. + the rank function, which is constructed "on the fly" (and is + session-dependent). See + :meth:`~sage.combinat.ordered_tree.normalize` for details. EXAMPLES:: @@ -225,11 +227,11 @@ def is_empty(self): r""" Return if ``self`` is the empty tree. - For rooted trees, returns always ``False`` + For rooted trees, this always returns ``False``. .. NOTE:: - This is not the same as ``bool(t)`` which returns whether + This is not the same as ``bool(t)``, which returns whether ``t`` has some child or not. EXAMPLES:: @@ -239,6 +241,11 @@ def is_empty(self): False sage: bool(t) True + sage: t = RootedTrees(1)([]) + sage: t.is_empty() + False + sage: bool(t) + False """ return False @@ -247,9 +254,11 @@ def graft_list(self, other): Return the list of trees obtained by grafting ``other`` on ``self``. Here grafting means that one takes the disjoint union of - ``self`` and ``other``, and add one edge from the root of - other to a vertex of ``self``. The root of the resulting - tree is the root of ``self``. + ``self`` and ``other``, chooses a node of ``self``, + and adds the root of ``other`` to the list of children of + this node. The root of the resulting tree is the root of + ``self``. (This can be done for each node of ``self``; + this method returns the list of all results.) This is useful for free pre-Lie algebras. @@ -260,14 +269,33 @@ def graft_list(self, other): sage: y = RT([x, x]) sage: x.graft_list(x) [[[]]] - sage: y.graft_list(x) + sage: l = y.graft_list(x); l + [[[], [], []], [[], [[]]], [[], [[]]]] + sage: [parent(i) for i in l] + [Rooted trees, Rooted trees, Rooted trees] + + TESTS:: + + sage: x = RootedTrees(1)([]) + sage: y = RootedTrees(3)([x, x]) + sage: l = y.graft_list(x); l [[[], [], []], [[], [[]]], [[], [[]]]] + sage: [parent(i) for i in l] + [Rooted trees, Rooted trees, Rooted trees] + + sage: x = RootedTree([[[], []], []]) + sage: y = RootedTree([[], []]) + sage: len(uniq(x.graft_list(y))) + 4 """ resu = [] + # Grafting ``other`` on the root: with self.clone() as t: t.append(other) resu += [t] for i, sub in enumerate(self): + # Grafting ``other`` on a descendant of the + # ``i``-th child: for new_sub in sub.graft_list(other): with self.clone() as t: t[i] = new_sub @@ -279,8 +307,8 @@ def graft_on_root(self, other): Return the tree obtained by grafting ``other`` on the root of ``self``. Here grafting means that one takes the disjoint union of - ``self`` and ``other``, and add one edge from the root of - other to the root of ``self``. The root of the resulting + ``self`` and ``other``, and adds the root of ``other`` to + the list of children of ``self``. The root of the resulting tree is the root of ``self``. This is useful for free Nap algebras. @@ -304,7 +332,7 @@ def graft_on_root(self, other): class RootedTrees(UniqueRepresentation, Parent): """ - Factory class for rooted trees + Factory class for rooted trees. INPUT: @@ -312,7 +340,8 @@ class RootedTrees(UniqueRepresentation, Parent): OUPUT: - - the set of all rooted trees (of the given ``size`` if specified) + the set of all rooted trees (of the given size ``size`` if + specified) EXAMPLES:: @@ -352,6 +381,11 @@ def __classcall_private__(cls, n=None): class RootedTrees_all(DisjointUnionEnumeratedSets, RootedTrees): + r""" + Class of all (unordered, unlabelled) rooted trees. + + See :class:`RootedTree` for a definition. + """ def __init__(self): """ @@ -494,7 +528,7 @@ def _an_element_(self): def __iter__(self): """ - An iterator for ``self`` + An iterator for ``self``. This generates the rooted trees of given size. The algorithm first picks a partition for the sizes of subtrees, then picks @@ -509,22 +543,22 @@ def __iter__(self): [[[]]] sage: RootedTrees(3).list() [[[[]]], [[], []]] + sage: RootedTrees(4).list() + [[[[[]]]], [[[], []]], [[], [[]]], [[], [], []]] """ if self._n == 1: yield self._element_constructor_([]) else: from sage.combinat.partition import Partitions - from sage.combinat.multichoose_nk import MultichooseNK - from sage.combinat.cartesian_product import CartesianProduct + from itertools import combinations_with_replacement, product for part in Partitions(self._n - 1): mults = part.to_exp_dict() choices = [] for p, mp in mults.items(): lp = self.__class__(p).list() - new_choice = MultichooseNK(len(lp), mp).map( - lambda l: [lp[i] for i in l]).list() + new_choice = [list(z) for z in combinations_with_replacement(lp, mp)] choices.append(new_choice) - for c in CartesianProduct(*choices): + for c in product(*choices): yield self._element_constructor_(sum(c, [])) def check_element(self, el, check=True): @@ -678,7 +712,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): def __classcall_private__(cls, *args, **opts): """ Ensure that trees created by the sets and directly are the same and - that they are instances of :class:`LabelledRootedTree` + that they are instances of :class:`LabelledRootedTree`. TESTS:: @@ -695,7 +729,7 @@ def __classcall_private__(cls, *args, **opts): @lazy_class_attribute def _auto_parent(cls): """ - The automatic parent of the element of this class + The automatic parent of the element of this class. When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. @@ -706,7 +740,7 @@ def _auto_parent(cls): Labelled rooted trees sage: LabelledRootedTree([], label = 3).parent() Labelled rooted trees - """ + """ return LabelledRootedTrees() _UnLabelled = RootedTree @@ -714,7 +748,8 @@ def _auto_parent(cls): class LabelledRootedTrees(UniqueRepresentation, Parent): """ - This is a parent stub to serve as a factory class for labelled rooted trees + This is a parent stub to serve as a factory class for labelled + rooted trees. EXAMPLES:: @@ -745,6 +780,12 @@ def __classcall_private__(cls, n=None): return LabelledRootedTrees_all() class LabelledRootedTrees_all(LabelledRootedTrees): + r""" + Class of all (unordered) labelled rooted trees. + + See :class:`LabelledRootedTree` for a definition. + """ + def __init__(self, category=None): """ TESTS:: From 90df275eea553fa5cf23b7989d2b12d2c0c18f14 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 21 Feb 2015 18:00:39 +0100 Subject: [PATCH 102/665] Initial package --- COPYING.txt | 1 + build/pkgs/threejs/SPKG.txt | 22 ++++++++++++++++++ build/pkgs/threejs/checksums.ini | 4 ++++ build/pkgs/threejs/package-version.txt | 1 + build/pkgs/threejs/spkg-install | 14 ++++++++++++ build/pkgs/threejs/spkg-src | 31 ++++++++++++++++++++++++++ 6 files changed, 73 insertions(+) create mode 100644 build/pkgs/threejs/SPKG.txt create mode 100644 build/pkgs/threejs/checksums.ini create mode 100644 build/pkgs/threejs/package-version.txt create mode 100755 build/pkgs/threejs/spkg-install create mode 100755 build/pkgs/threejs/spkg-src diff --git a/COPYING.txt b/COPYING.txt index c74fb76301b..c9c94768f95 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -123,6 +123,7 @@ sympow Modified BSD sympy Modified BSD tachyon Modified BSD termcap GPLv2+ +threejs MIT License tornado Apache License zlib Custom (Modified BSD) zn_poly GPLv2 or GPLv3 (no later versions, see below) diff --git a/build/pkgs/threejs/SPKG.txt b/build/pkgs/threejs/SPKG.txt new file mode 100644 index 00000000000..37bdee51f52 --- /dev/null +++ b/build/pkgs/threejs/SPKG.txt @@ -0,0 +1,22 @@ += MathJax = + +== Description == + +Three.js is a javascript library to display 3-d graphics in the browser. + +== License == + +MIT License + +== Upstream Contact == + +Home page: http://threejs.org + +== Dependencies == + +None. + +== Special Update/Build Instructions == + +None. + diff --git a/build/pkgs/threejs/checksums.ini b/build/pkgs/threejs/checksums.ini new file mode 100644 index 00000000000..07766bfd0c6 --- /dev/null +++ b/build/pkgs/threejs/checksums.ini @@ -0,0 +1,4 @@ +tarball=threejs-VERSION.tar.gz +sha1=1dc6a7461b8d87bdabd31f3b4c532b1c1bfec9eb +md5=1893273d0abdb79d52898a478c3dec59 +cksum=2984618453 diff --git a/build/pkgs/threejs/package-version.txt b/build/pkgs/threejs/package-version.txt new file mode 100644 index 00000000000..41ab1704588 --- /dev/null +++ b/build/pkgs/threejs/package-version.txt @@ -0,0 +1 @@ +r70 diff --git a/build/pkgs/threejs/spkg-install b/build/pkgs/threejs/spkg-install new file mode 100755 index 00000000000..63ddcdc4868 --- /dev/null +++ b/build/pkgs/threejs/spkg-install @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Check required environment variable +if [ -z "$SAGE_SHARE" ]; then + echo >&2 "SAGE_SHARE undefined ... exiting" + echo >&2 "Maybe run 'sage --sh'?" + exit 1 +fi + +# Copy files +TARGET="${SAGE_SHARE}/threejs" +rm -rf "${TARGET}" +cp -r 'src' "${TARGET}" + diff --git a/build/pkgs/threejs/spkg-src b/build/pkgs/threejs/spkg-src new file mode 100755 index 00000000000..d3a6df28142 --- /dev/null +++ b/build/pkgs/threejs/spkg-src @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e + +GIT_VERSION=r70 + +[ -n "${SAGE_ROOT}" ] || SAGE_ROOT="$(pwd)/../../../" + + +# fetch and rename latest version. +URL="https://github.com/mrdoob/three.js/archive/${GIT_VERSION}.tar.gz" +echo "Downloading $URL" +rm -rf src +if [ -z "$UPSTREAM_SOURCE_TARBALL" ]; then + tar xzf <( curl -L "$URL" ) +else + tar xzf "$UPSTREAM_SOURCE_TARBALL" +fi +mv three.js-${GIT_VERSION} src + +# Delete the 200mb of enclosed examples +rm -rf src/examples + +# repack +tar czf "$SAGE_ROOT/upstream/threejs-${GIT_VERSION}.tar.gz" src +rm -rf src + +# update package info +echo "${GIT_VERSION}" > 'package-version.txt' +"$SAGE_ROOT"/sage -sh 'sage-fix-pkg-checksums' + From 7d3a46f508c992e6b0c4b5b406ce3eaea2326f01 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 21 Feb 2015 20:10:56 +0100 Subject: [PATCH 103/665] keep the examples/js directory --- build/pkgs/threejs/checksums.ini | 6 +++--- build/pkgs/threejs/spkg-src | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/pkgs/threejs/checksums.ini b/build/pkgs/threejs/checksums.ini index 07766bfd0c6..e9d8e598bcb 100644 --- a/build/pkgs/threejs/checksums.ini +++ b/build/pkgs/threejs/checksums.ini @@ -1,4 +1,4 @@ tarball=threejs-VERSION.tar.gz -sha1=1dc6a7461b8d87bdabd31f3b4c532b1c1bfec9eb -md5=1893273d0abdb79d52898a478c3dec59 -cksum=2984618453 +sha1=274f03baabe81dbc90ba64a8883c395a2425b649 +md5=afae707a2e79d2c85cee1132b0bf3bd2 +cksum=1616666612 diff --git a/build/pkgs/threejs/spkg-src b/build/pkgs/threejs/spkg-src index d3a6df28142..9f43ad9d416 100755 --- a/build/pkgs/threejs/spkg-src +++ b/build/pkgs/threejs/spkg-src @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -e +shopt -s extglob GIT_VERSION=r70 @@ -19,7 +20,8 @@ fi mv three.js-${GIT_VERSION} src # Delete the 200mb of enclosed examples -rm -rf src/examples +# However, keep the examples/js directory (see Trac #17823) +rm -rf src/examples/!(js) # repack tar czf "$SAGE_ROOT/upstream/threejs-${GIT_VERSION}.tar.gz" src From 30543e7b283c52cad2fbeb060efe78a74c7b42ba Mon Sep 17 00:00:00 2001 From: Simon King Date: Sat, 21 Feb 2015 20:45:59 +0100 Subject: [PATCH 104/665] Avoid source inspection for cached cython methods without arguments --- src/sage/misc/cachefunc.pyx | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index a4276b99a4b..b318139464f 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -472,10 +472,17 @@ the parent as its first argument:: # # http://www.gnu.org/licenses/ ######################################################################## +from cpython cimport PyObject + +cdef extern from "methodobject.h": + cdef int METH_NOARGS, METH_O + cdef int PyCFunction_GetFlags(object op) except -1 + from function_mangling import ArgumentFixer import os from os.path import relpath,normpath,commonprefix from sage.misc.sageinspect import sage_getfile, sage_getsourcelines, sage_getargspec +from inspect import isfunction import sage.misc.weak_dict from sage.misc.weak_dict import WeakValueDictionary @@ -2671,18 +2678,22 @@ cdef class CachedMethod(object): # Since we have an optimized version for functions that do not accept arguments, # we need to analyse the argspec f = (self._cachedfunc).f - if self.nargs==0: - args, varargs, keywords, defaults = sage_getargspec(f) - if varargs is None and keywords is None and len(args)<=1: - self.nargs = 1 - Caller = CachedMethodCallerNoArgs(inst, f, name=name) - else: - self.nargs = 2 # don't need the exact number - Caller = CachedMethodCaller(self, inst, - cache=self._get_instance_cache(inst), - name=name, - key=self._cachedfunc.key) - elif self.nargs==1: + if self.nargs == 0: + if isinstance(f, object) and not isfunction(f): + try: + if METH_NOARGS&PyCFunction_GetFlags(f.__get__(inst,cls)): + self.nargs = 1 + else: + self.nargs = 2 + except: + pass + if self.nargs == 0: + args, varargs, keywords, defaults = sage_getargspec(f) + if varargs is None and keywords is None and len(args)<=1: + self.nargs = 1 + else: + self.nargs = 2 # don't need the exact number + if self.nargs == 1: Caller = CachedMethodCallerNoArgs(inst, f, name=name) else: Caller = CachedMethodCaller(self, inst, From a0b829dc10b4ccb00b99e073de8a1c0006aa1e51 Mon Sep 17 00:00:00 2001 From: Simon King Date: Sun, 22 Feb 2015 11:20:05 +0100 Subject: [PATCH 105/665] Make a cached function/method work with default argspec when introspection fails --- src/sage/misc/function_mangling.pyx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index 97a3d0fc6e2..83ab48bdfe9 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -121,7 +121,21 @@ cdef class ArgumentFixer: cdef dict _defaults cdef public tuple _default_tuple def __init__(self, f, classmethod = False): - arg_names, varargs, varkw, defaults = sage_getargspec(f) + try: + arg_names, varargs, varkw, defaults = sage_getargspec(f) + except AttributeError: + # This error occurs if f is defined in a Cython file and the + # source file has gone. + if classmethod: + arg_names = ['self'] + varargs = 'args' + varkws = 'kwds' + defaults = None + else: + arg_names = [] + varargs = 'args' + varkws = 'kwds' + defaults = None if defaults is None: self._default_tuple = defaults = () else: From 1bb609e987084b1fc08cd4d23ed7add21069adea Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 23 Feb 2015 17:19:00 +0100 Subject: [PATCH 106/665] Show tracebacks in unpickle_all() --- src/sage/structure/sage_object.pyx | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index a5506b7723e..2be0f7142a2 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -1032,24 +1032,6 @@ def register_unpickle_override(module, name, callable, call_name=None): you can specify the module name and class name, for the benefit of :func:`~sage.misc.explain_pickle.explain_pickle` when called with ``in_current_sage=True``).) - EXAMPLES:: - - sage: from sage.structure.sage_object import unpickle_override, register_unpickle_override - sage: unpickle_global('sage.rings.integer', 'Integer') - - - Now we horribly break the pickling system:: - - sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational')) - sage: unpickle_global('sage.rings.integer', 'Integer') - - - and we reach into the internals and put it back:: - - sage: del unpickle_override[('sage.rings.integer', 'Integer')] - sage: unpickle_global('sage.rings.integer', 'Integer') - - In many cases, unpickling problems for old pickles can be resolved with a simple call to ``register_unpickle_override``, as in the example above and in many of the ``sage`` source files. However, if the underlying data @@ -1491,12 +1473,14 @@ def unpickle_all(dir = None, debug=False, run_test_suite=False): if run_test_suite: TestSuite(object).run(catch = False) i += 1 - except Exception as msg: + except Exception: j += 1 if run_test_suite: print " * unpickle failure: TestSuite(load('%s')).run()"%os.path.join(dir,A) else: print " * unpickle failure: load('%s')"%os.path.join(dir,A) + from traceback import print_exc + print_exc() failed.append(A) if debug: tracebacks.append(sys.exc_info()) From 554020502657566ed334823ac0d36e39b2fcb22d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Feb 2015 12:23:12 -0800 Subject: [PATCH 107/665] Some minor reviewer tweaks. --- src/sage/combinat/ordered_tree.py | 32 +++++++-------- src/sage/combinat/rooted_tree.py | 65 +++++++++++++------------------ 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 4431e5a3527..9f0888c0ad8 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -606,16 +606,16 @@ def dendrog_cmp(self, other): INPUT: - - ``other``: an ordered rooted tree. + - ``other`` -- an ordered rooted tree OUTPUT: - `-1`, if ``smaller < other`` with respect to the - dendrographical order. - `0`, if ``smaller == other`` (as unlabelled ordered - rooted trees). - `1`, if ``smaller > other`` with respect to the - dendrographical order. + - `-1`, if ``smaller < other`` with respect to the + dendrographical order. + - `0`, if ``smaller == other`` (as unlabelled ordered + rooted trees). + - `1`, if ``smaller > other`` with respect to the + dendrographical order. .. NOTE:: @@ -660,9 +660,9 @@ def dendrog_normalize(self, inplace=False): INPUT: - - ``inplace`` -- boolean, (default ``False``) if ``True``, - then ``self`` is modified and nothing returned. Otherwise - the normalized tree is returned. + - ``inplace`` -- (default ``False``) boolean; if ``True``, + then ``self`` is modified and nothing returned; otherwise + the normalized tree is returned The normalized tree of an unlabelled ordered rooted tree `t` with respect to the dendrographical order is an @@ -709,11 +709,11 @@ def dendrog_cmp(a, b): resl[i] = resl[i].dendrog_normalize() resl.sort(cmp=dendrog_cmp) return res - else: - resl = self._get_list() - for i in range(len(resl)): - resl[i] = resl[i].dendrog_normalize() - resl.sort(cmp=dendrog_cmp) + + resl = self._get_list() + for i in range(len(resl)): + resl[i] = resl[i].dendrog_normalize() + resl.sort(cmp=dendrog_cmp) # Abstract class to serve as a Factory no instance are created. @@ -818,7 +818,7 @@ def __init__(self): sage: B is OrderedTrees_all() True - sage: TestSuite(B).run() + sage: TestSuite(B).run() # long time """ DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), OrderedTrees_size), diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index da99a67e048..813616189e4 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -3,7 +3,7 @@ AUTHORS: -- Florent Hivert (2011): initial revision +- Florent Hivert (2011): initial version """ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets @@ -13,7 +13,6 @@ from sage.misc.cachefunc import cached_function from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute -from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets @@ -171,9 +170,8 @@ def __init__(self, parent=None, children=[], check=True): children = list(children) except TypeError: raise TypeError("input ({}) is not a valid tree".format(children)) - tst = (children.__class__ is self.__class__ - and children.parent() == parent) - if not tst: + if not (children.__class__ is self.__class__ + and children.parent() == parent): children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) @@ -374,10 +372,10 @@ def __classcall_private__(cls, n=None): """ if n is None: return RootedTrees_all() - else: - if not (isinstance(n, (Integer, int)) and n >= 1): - raise ValueError("n must be a positive integer") - return RootedTrees_size(Integer(n)) + + if n not in ZZ or n < 1: + raise ValueError("n must be a positive integer") + return RootedTrees_size(Integer(n)) class RootedTrees_all(DisjointUnionEnumeratedSets, RootedTrees): @@ -386,20 +384,17 @@ class RootedTrees_all(DisjointUnionEnumeratedSets, RootedTrees): See :class:`RootedTree` for a definition. """ - def __init__(self): """ TESTS:: - sage: from sage.combinat.rooted_tree import RootedTrees_all - sage: sum(x**len(t) for t in ....: set(RootedTree(t) for t in OrderedTrees(6))) x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x sage: sum(x**len(t) for t in RootedTrees(6)) x^5 + x^4 + 3*x^3 + 6*x^2 + 9*x - sage: TestSuite(RootedTrees()).run() + sage: TestSuite(RootedTrees()).run() # long time """ DisjointUnionEnumeratedSets.__init__( self, Family(NonNegativeIntegers(), RootedTrees_size), @@ -409,7 +404,7 @@ def _repr_(self): r""" TESTS:: - sage: RootedTrees() # indirect doctest + sage: RootedTrees() Rooted trees """ return "Rooted trees" @@ -548,18 +543,19 @@ def __iter__(self): """ if self._n == 1: yield self._element_constructor_([]) - else: - from sage.combinat.partition import Partitions - from itertools import combinations_with_replacement, product - for part in Partitions(self._n - 1): - mults = part.to_exp_dict() - choices = [] - for p, mp in mults.items(): - lp = self.__class__(p).list() - new_choice = [list(z) for z in combinations_with_replacement(lp, mp)] - choices.append(new_choice) - for c in product(*choices): - yield self._element_constructor_(sum(c, [])) + return + + from sage.combinat.partition import Partitions + from itertools import combinations_with_replacement, product + for part in Partitions(self._n - 1): + mults = part.to_exp_dict() + choices = [] + for p, mp in mults.items(): + lp = self.__class__(p).list() + new_choice = [list(z) for z in combinations_with_replacement(lp, mp)] + choices.append(new_choice) + for c in product(*choices): + yield self.element_class(self._parent_for, sum(c, [])) def check_element(self, el, check=True): r""" @@ -766,7 +762,7 @@ class LabelledRootedTrees(UniqueRepresentation, Parent): .. TODO:: - add the possibility to restrict the labels to a fixed set. + Add the possibility to restrict the labels to a fixed set. """ @staticmethod def __classcall_private__(cls, n=None): @@ -794,6 +790,7 @@ def __init__(self, category=None): """ if category is None: category = Sets() + category = category.Infinite() Parent.__init__(self, category=category) def _repr_(self): @@ -802,22 +799,11 @@ def _repr_(self): TESTS:: - sage: LabelledRootedTrees() # indirect doctest + sage: LabelledRootedTrees() Labelled rooted trees """ return "Labelled rooted trees" - def cardinality(self): - """ - Return the cardinality of ``self``. - - EXAMPLE:: - - sage: LabelledRootedTrees().cardinality() - +Infinity - """ - return Infinity - def _an_element_(self): """ Return a labelled tree. @@ -856,3 +842,4 @@ def labelled_trees(self): return self Element = LabelledRootedTree + From 1c377ad3988c9ac47e54922a6722fd714b2a7e3d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 27 Feb 2015 23:49:54 -0800 Subject: [PATCH 108/665] One last fix for a unless check. --- src/sage/combinat/rooted_tree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 813616189e4..646e68b13e8 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -170,9 +170,9 @@ def __init__(self, parent=None, children=[], check=True): children = list(children) except TypeError: raise TypeError("input ({}) is not a valid tree".format(children)) - if not (children.__class__ is self.__class__ - and children.parent() == parent): - children = [self.__class__(parent, x) for x in children] + #if not (children.__class__ is self.__class__ + # and children.parent() == parent): + children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) _unordered_ranker = on_fly() From 5495f28ade69139f3a065ae866fcace44bf110ea Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 13:54:28 -0700 Subject: [PATCH 109/665] semi simple commutative decomposition bugged code --- src/sage/categories/groups.py | 1 + src/sage/categories/semisimple_algebras.py | 73 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index adabc4f02ba..3d88ad91550 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -684,6 +684,7 @@ def _conjugacy_classes_representatives_underlying_group(self): """ return self.group().conjugacy_classes_representatives() + @cached_method def center_basis(self): r""" Return a basis of the center of the group algebra. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index f657c2f587e..42049f73214 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -9,10 +9,13 @@ #****************************************************************************** from category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from algebras import Algebras from sage.misc.cachefunc import cached_method import operator +from sage.rings.integer_ring import ZZ + class SemisimpleAlgebras(Category_over_base_ring): """ The category of semisimple algebras over a given base ring. @@ -53,3 +56,73 @@ def super_categories(self): """ R = self.base_ring() return [Algebras(R)] + + class Commutative(CategoryWithAxiom_over_base_ring): + + from sage.rings.integer_ring import ZZ + from sage.categories.associative_algebras import AssociativeAlgebras + + class ParentMethods: + + def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): + r""" + Decompose a commutative semi-simple algebra ``A`` into a direct sum of simple A-modules. + + Return a list of generators of simple A-modules. + + EXAMPLES: + + sage: A5 = SymmetricGroupAlgebra(QQ,5) + sage: Z5 = A5.center() + sage: semi_simple_commutative_decomposition(Z5) + [B[0] - 1/3*B[3] + 1/6*B[6], + B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], + B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6], + B[0] + 1/2*B[1] + 1/4*B[2] - 1/4*B[5] - 1/4*B[6], + B[0] - 1/2*B[1] + 1/4*B[2] + 1/4*B[5] - 1/4*B[6], + B[0] + 1/5*B[1] - 1/5*B[2] + 1/5*B[3] - 1/5*B[4] + 1/5*B[5], + B[0] - 1/5*B[1] - 1/5*B[2] + 1/5*B[3] + 1/5*B[4] - 1/5*B[5]] + """ + #Terminal case and stuffs + if listGen==None: + listGen = self.basis().list() + if self.dimension() == 1: + if topLevel: + return self.basis().list() + else: + return [x.lift() for x in self.basis()] + + #Searching for a good generator... + res = [] + B = self.basis() + while len(res)<2: + if listGen==[]: + raise Exception("Unable to fully decompose...") + curGen = listGen[ZZ.random_element(len(listGen))] + listGen.remove(curGen) + phi = self.module_morphism(on_basis=lambda i: + curGen*B[i], + codomain=self, + triangular=True) + # phi = self.module_morphism(on_basis=lambda i: + # curGen*self.monomial(i), + # codomain=self, + # triangular=True) + return phi + aMat = phi.matrix(self.base_ring()) + res = aMat.eigenspaces_right() + + #Gotcha! Let's settle the algebra... + + res = [vector_space for _,vector_space in res] + res = [[self.from_vector(vector) for vector in eigenspace.basis()] + for eigenspace in res] + + decomp = [self.submodule(v, category=AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects()) for v in res] + + #Recursive on decomp + res = [x for space in decomp for x in space.semi_simple_commutative_decomposition(topLevel=False)] + if topLevel: + return res + else: + return map( lambda x: x.lift(), res) From 572f5480a53dd6a34f73f042f0ffa141eb7eb403 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 18:25:00 -0700 Subject: [PATCH 110/665] SemisimpleAlgebras, orthogonal idempotents for commutative semisimple algebras --- .../finite_dimensional_modules_with_basis.py | 2 +- src/sage/categories/groups.py | 1 + src/sage/categories/semisimple_algebras.py | 88 +++++++++++++------ 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 65f10177f82..7a045b21fb9 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -273,7 +273,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis() + on_basis = self.on_basis basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 3d88ad91550..bdfdfc0074d 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -13,6 +13,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport +from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.monoids import Monoids from sage.categories.algebra_functor import AlgebrasCategory diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 42049f73214..7ce5f6c2b46 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -10,12 +10,12 @@ from category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from algebras import Algebras from sage.misc.cachefunc import cached_method -import operator - +from algebras import Algebras +from sage.categories.associative_algebras import AssociativeAlgebras from sage.rings.integer_ring import ZZ + class SemisimpleAlgebras(Category_over_base_ring): """ The category of semisimple algebras over a given base ring. @@ -59,29 +59,42 @@ def super_categories(self): class Commutative(CategoryWithAxiom_over_base_ring): - from sage.rings.integer_ring import ZZ - from sage.categories.associative_algebras import AssociativeAlgebras - class ParentMethods: - def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): + @cached_method + def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): r""" - Decompose a commutative semi-simple algebra ``A`` into a direct sum of simple A-modules. + Decompose a commutative finite dimensional semi-simple algebra + ``A`` into a direct sum of simple A-modules. + + INPUT:: + + - ``self`` a finite dimensional semisimple commutative algebra. + + OUTPUT:: + + - list of elements of ``self`` each generating a simple + submodule of ``self`` in direct sum with the others. The list + is maximal. Return a list of generators of simple A-modules. EXAMPLES: - sage: A5 = SymmetricGroupAlgebra(QQ,5) - sage: Z5 = A5.center() - sage: semi_simple_commutative_decomposition(Z5) - [B[0] - 1/3*B[3] + 1/6*B[6], - B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], - B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6], - B[0] + 1/2*B[1] + 1/4*B[2] - 1/4*B[5] - 1/4*B[6], - B[0] - 1/2*B[1] + 1/4*B[2] + 1/4*B[5] - 1/4*B[6], - B[0] + 1/5*B[1] - 1/5*B[2] + 1/5*B[3] - 1/5*B[4] + 1/5*B[5], - B[0] - 1/5*B[1] - 1/5*B[2] + 1/5*B[3] + 1/5*B[4] - 1/5*B[5]] + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: Z5._semi_simple_commutative_decomposition_generators() + [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + B[3] + + B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - + 1/5*B[5], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - + 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] """ #Terminal case and stuffs if listGen==None: @@ -104,11 +117,6 @@ def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): curGen*B[i], codomain=self, triangular=True) - # phi = self.module_morphism(on_basis=lambda i: - # curGen*self.monomial(i), - # codomain=self, - # triangular=True) - return phi aMat = phi.matrix(self.base_ring()) res = aMat.eigenspaces_right() @@ -118,11 +126,41 @@ def semi_simple_commutative_decomposition(self, listGen=None, topLevel=True): res = [[self.from_vector(vector) for vector in eigenspace.basis()] for eigenspace in res] - decomp = [self.submodule(v, category=AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects()) for v in res] + decomp = [self.submodule(v, + category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] #Recursive on decomp - res = [x for space in decomp for x in space.semi_simple_commutative_decomposition(topLevel=False)] + res = [x for space in decomp for x in + space._semi_simple_commutative_decomposition_generators(topLevel=False)] if topLevel: return res else: return map( lambda x: x.lift(), res) + + @cached_method + r""" + Return the minimal orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z5.orthogonal_idempotents() + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], + 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + + 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - + 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + """ + def orthogonal_idempotents(self): + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in + self._semi_simple_commutative_decomposition_generators()] From eff3169a8379c2eaa645dadc6b437ac4b757fcf9 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 18:30:49 -0700 Subject: [PATCH 111/665] indentation --- src/sage/categories/semisimple_algebras.py | 45 +++++++++++----------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 7ce5f6c2b46..279c9c1fcb9 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -138,29 +138,30 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev return map( lambda x: x.lift(), res) @cached_method - r""" - Return the minimal orthogonal idempotents of ``self``. - - EXAMPLES:: - - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + - 45*B[6] - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z5.orthogonal_idempotents() - sage: orth - [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + - 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], - 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + - 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - - 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] - """ def orthogonal_idempotents(self): + r""" + Return the minimal orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: Z5.an_element() ** 2 + 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + + 45*B[6] + sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z5.orthogonal_idempotents() + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], + 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + + 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - + 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] From d69e9825c05627c607099d851ec8d8471b8cbf26 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 19:35:30 -0700 Subject: [PATCH 112/665] tests --- src/sage/categories/semisimple_algebras.py | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 279c9c1fcb9..69fdb0d24c7 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -88,13 +88,14 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) - sage: Z5._semi_simple_commutative_decomposition_generators() - [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + B[3] + - B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] - + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - - 1/5*B[5], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] - + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - - 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] + sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: sorted(gens, key=str) + [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] + + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], B[0] - 1/2*B[1] + + 1/4*B[3] + 1/4*B[4] - 1/4*B[6], B[0] - 1/3*B[2] + + 1/6*B[6], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6]] """ #Terminal case and stuffs if listGen==None: @@ -152,15 +153,17 @@ def orthogonal_idempotents(self): 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() - sage: orth - [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + - 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], - 1/120*B[0] - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5], 2/15*B[0] + - 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - - 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] + sage: orth = Z5.orthogonal_idempotents() + sage: sorted(orth, key=str) + [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - + 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] + - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + 1/30*B[3] + + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - 1/10*B[2] + 1/20*B[6], + 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - + 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - + 1/24*B[4] + 1/24*B[5]] """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in From 35c5330b3c84738845441d2576269af576a0cbca Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 24 Jul 2014 21:56:14 -0700 Subject: [PATCH 113/665] _lift_idempotent for elements of sub-algebras --- src/sage/categories/algebras.py | 51 +++++++++++++++++++ .../finite_dimensional_algebras_with_basis.py | 4 ++ src/sage/categories/semisimple_algebras.py | 18 ++++--- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 5c9f6463ddc..75e031f0b34 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -218,3 +218,54 @@ def extra_super_categories(self): """ from sage.categories.coalgebras import Coalgebras return [Coalgebras(self.base_category().base_ring())] + + + class Subobjects(SubobjectsCategory): + + class ElementMethods: + + def _mul_(self, right): + r""" + Product of two elements. + INPUT:: + + - ``self``, ``right`` -- two elements + + If B is a SubModuleWithBasis of A, then the multiplication law of B is + inherited from the multiplication of A. + + EXAMPLES:: + + sage: Z = SymmetricGroup(5).algebra(QQ).center() + sage: B = Z.basis() + sage: B[3] * B[2] + 4*B[2] + 6*B[3] + 5*B[6] + """ + p = self.parent() + return p.retract( self.lift() * right.lift()) + + def _lift_idempotent(self): + r""" + Lift an idempotent of parent of ``self`` into an indempotent of + parent of ``self.lift()`` + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: Z3 = A3.center() + sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z3.orthogonal_idempotents() + sage: x = orth[2]._lift_idempotent() + sage: x not in Z3 and x in A3 + True + + TODO: better documentation. + """ + idempOld = None + idemp = self.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 46bdb05703b..50f526f562f 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -347,6 +347,10 @@ def center(self): center.rename("Center of {}".format(self)) return center + # def orthogonal_idempotents(self): + # pass + + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 69fdb0d24c7..d440b82d124 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -84,9 +84,6 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] - + 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: gens = Z5._semi_simple_commutative_decomposition_generators() sage: sorted(gens, key=str) @@ -143,14 +140,19 @@ def orthogonal_idempotents(self): r""" Return the minimal orthogonal idempotents of ``self``. + INPUT:: + + - ``self`` a commutative semisimple algebra + + OUTPUT:: + + - list of idempotents of ``self`` + EXAMPLES:: sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5.an_element() ** 2 - 179*B[0] + 44*B[1] + 38*B[2] + 39*B[3] + 36*B[4] + 24*B[5] + - 45*B[6] sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() sage: orth = Z5.orthogonal_idempotents() @@ -164,6 +166,10 @@ def orthogonal_idempotents(self): 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + 1/24*B[5]] + sage: orth[2] * orth[4] + 0 + sage: orth[1] ** 2 == orth[1] + True """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in From 4d6ab0893b977638a5e25c0e02a71012366cabb9 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 10:32:47 -0700 Subject: [PATCH 114/665] orthogonal idempotents for semisimple algebras --- .../finite_dimensional_algebras_with_basis.py | 12 +++---- src/sage/categories/groups.py | 1 - src/sage/categories/semisimple_algebras.py | 32 ++++++++++++++++--- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 50f526f562f..180f083c6c5 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -338,20 +338,18 @@ def center(self): sage: TestSuite(center).run() """ - category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() - if self in SemisimpleAlgebras: - category = category & SemisimpleAlgebras(self.base_ring()) + if self in SemisimpleAlgebras(self.base_ring()): + category = SemisimpleAlgebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() + else: + category = Algebras(self.base_ring()).FiniteDimensional().WithBasis().Subobjects().Commutative() center = self.submodule(self.center_basis(), category = category, already_echelonized = True) center.rename("Center of {}".format(self)) return center - # def orthogonal_idempotents(self): - # pass - - class ElementMethods: + def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ Return the matrix of the action of ``self`` on the algebra. diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index bdfdfc0074d..6a905fc5a58 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -685,7 +685,6 @@ def _conjugacy_classes_representatives_underlying_group(self): """ return self.group().conjugacy_classes_representatives() - @cached_method def center_basis(self): r""" Return a basis of the center of the group algebra. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index d440b82d124..90e8147c46d 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -57,6 +57,32 @@ def super_categories(self): R = self.base_ring() return [Algebras(R)] + class ParentMethods: + + @cached_method + def orthogonal_idempotents(self): + r""" + Return a maximal list of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- semisimple algebra + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: orth3 = A3.orthogonal_idempotents() + sage: sorted(orth3, key=str) + [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], + 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + """ + Z = self.center() + orth = Z.orthogonal_idempotents() + return [x._lift_idempotent() for x in orth] + + class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -67,11 +93,11 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev Decompose a commutative finite dimensional semi-simple algebra ``A`` into a direct sum of simple A-modules. - INPUT:: + INPUT: - ``self`` a finite dimensional semisimple commutative algebra. - OUTPUT:: + OUTPUT: - list of elements of ``self`` each generating a simple submodule of ``self`` in direct sum with the others. The list @@ -84,7 +110,6 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: gens = Z5._semi_simple_commutative_decomposition_generators() sage: sorted(gens, key=str) [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + @@ -153,7 +178,6 @@ def orthogonal_idempotents(self): sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: Z5._refine_category_(SemisimpleAlgebras(QQ)) sage: orth = Z5.orthogonal_idempotents() sage: orth = Z5.orthogonal_idempotents() sage: sorted(orth, key=str) From d9446d3e057b6c9963b9357107cdd4c171326e70 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 10:38:39 -0700 Subject: [PATCH 115/665] tests --- src/sage/categories/semisimple_algebras.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 90e8147c46d..5bfafd73b44 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -77,10 +77,21 @@ def orthogonal_idempotents(self): 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + + :: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: sorted(orth, key=str) + [B['x'], B['y']] """ Z = self.center() orth = Z.orthogonal_idempotents() - return [x._lift_idempotent() for x in orth] + return [x.lift() for x in orth] class Commutative(CategoryWithAxiom_over_base_ring): From 3e7a5842454a1149e072b4b843ae6886669f49c0 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 25 Jul 2014 11:33:32 -0700 Subject: [PATCH 116/665] beginning of implemantation for general algebras --- src/sage/categories/algebras.py | 54 ++++++++++--------- .../finite_dimensional_algebras_with_basis.py | 12 +++++ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 75e031f0b34..f077b59b246 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -119,6 +119,34 @@ def _div_(self, y): class Quotients(QuotientsCategory): + class ElementMethods: + + def _lift_idempotent(self): + r""" + Lift an idempotent of parent of ``self`` into an indempotent of + parent of ``self.lift()`` + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: Z3 = A3.center() + sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) + sage: orth = Z3.orthogonal_idempotents() + sage: x = orth[2]._lift_idempotent() + sage: x not in Z3 and x in A3 + True + + TODO: better documentation. + """ + idempOld = None + idemp = self.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp + class ParentMethods: def algebra_generators(self): @@ -243,29 +271,3 @@ def _mul_(self, right): """ p = self.parent() return p.retract( self.lift() * right.lift()) - - def _lift_idempotent(self): - r""" - Lift an idempotent of parent of ``self`` into an indempotent of - parent of ``self.lift()`` - - EXAMPLES:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: Z3 = A3.center() - sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z3.orthogonal_idempotents() - sage: x = orth[2]._lift_idempotent() - sage: x not in Z3 and x in A3 - True - - TODO: better documentation. - """ - idempOld = None - idemp = self.lift() - p = idemp.parent() - while idemp <> idempOld: - tmp = idemp - idemp = (p.one() - (p.one() - idemp**2)**2) - idempOld = tmp - return idemp diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 180f083c6c5..71ee5bf2663 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -348,6 +348,18 @@ def center(self): center.rename("Center of {}".format(self)) return center + def orthogonal_idempotent(self): + r""" + Return a maximal family of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- a finite dimensional algebra + """ + Aquo = self.semisimple_quotient() + orth_quo = Aquo.orthogonal_idempotents() + return [x._lift_idempotent() for x in orth_quo] + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): From 2d98764aa0e4b21db140519acb8f4134c3225e95 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 30 Jul 2014 11:39:42 -0700 Subject: [PATCH 117/665] radical for SemisimpleAlgebras --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 71ee5bf2663..65016299007 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -147,6 +147,9 @@ def radical_basis(self, cache_products=True): from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + if self in SemisimpleAlgebras(self.base_ring()): + return self.from_vector(vector(self.zero())) + if cache_products is True: product_on_basis = cached_function(self.product_on_basis) else: From a6571513b135257874b65f7f1f95bf4b9e584de1 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 11 Aug 2014 18:13:53 -0700 Subject: [PATCH 118/665] example --- .../finite_dimensional_algebras_with_basis.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 65016299007..e575cbf6f2b 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -358,6 +358,16 @@ def orthogonal_idempotent(self): INPUT: - ``self`` -- a finite dimensional algebra + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: A.orthogonal_idempotent() + [y, x] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() From 2405b9f5dae5c59c7754d62e19460fc64e4b78a7 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:04:59 +0200 Subject: [PATCH 119/665] orthogonal idempotents for all finitedimensional algebras with basis --- .../finite_dimensional_algebras_with_basis.py | 2 +- src/sage/categories/semisimple_algebras.py | 313 +++++++++--------- 2 files changed, 162 insertions(+), 153 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index e575cbf6f2b..463ea706cdf 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -351,7 +351,7 @@ def center(self): center.rename("Center of {}".format(self)) return center - def orthogonal_idempotent(self): + def orthogonal_idempotents(self): r""" Return a maximal family of orthogonal idempotents of ``self``. diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 5bfafd73b44..019f746455a 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -57,155 +57,164 @@ def super_categories(self): R = self.base_ring() return [Algebras(R)] - class ParentMethods: - - @cached_method - def orthogonal_idempotents(self): - r""" - Return a maximal list of orthogonal idempotents of ``self``. - - INPUT: - - - ``self`` -- semisimple algebra - - EXAMPLES:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: orth3 = A3.orthogonal_idempotents() - sage: sorted(orth3, key=str) - [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + - 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], - 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] - - :: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path - algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field - sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.orthogonal_idempotents() - sage: sorted(orth, key=str) - [B['x'], B['y']] - """ - Z = self.center() - orth = Z.orthogonal_idempotents() - return [x.lift() for x in orth] - - - class Commutative(CategoryWithAxiom_over_base_ring): - - class ParentMethods: - - @cached_method - def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): - r""" - Decompose a commutative finite dimensional semi-simple algebra - ``A`` into a direct sum of simple A-modules. - - INPUT: - - - ``self`` a finite dimensional semisimple commutative algebra. - - OUTPUT: - - - list of elements of ``self`` each generating a simple - submodule of ``self`` in direct sum with the others. The list - is maximal. - - Return a list of generators of simple A-modules. - - EXAMPLES: - - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: gens = Z5._semi_simple_commutative_decomposition_generators() - sage: sorted(gens, key=str) - [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] - + B[1] + B[2] + B[3] + B[4] + B[5] + B[6], B[0] - 1/2*B[1] - + 1/4*B[3] + 1/4*B[4] - 1/4*B[6], B[0] - 1/3*B[2] + - 1/6*B[6], B[0] - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] - + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + B[6]] - """ - #Terminal case and stuffs - if listGen==None: - listGen = self.basis().list() - if self.dimension() == 1: - if topLevel: - return self.basis().list() - else: - return [x.lift() for x in self.basis()] - - #Searching for a good generator... - res = [] - B = self.basis() - while len(res)<2: - if listGen==[]: - raise Exception("Unable to fully decompose...") - curGen = listGen[ZZ.random_element(len(listGen))] - listGen.remove(curGen) - phi = self.module_morphism(on_basis=lambda i: - curGen*B[i], - codomain=self, - triangular=True) - aMat = phi.matrix(self.base_ring()) - res = aMat.eigenspaces_right() - - #Gotcha! Let's settle the algebra... - - res = [vector_space for _,vector_space in res] - res = [[self.from_vector(vector) for vector in eigenspace.basis()] - for eigenspace in res] - - decomp = [self.submodule(v, - category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] - - #Recursive on decomp - res = [x for space in decomp for x in - space._semi_simple_commutative_decomposition_generators(topLevel=False)] - if topLevel: - return res - else: - return map( lambda x: x.lift(), res) - - @cached_method - def orthogonal_idempotents(self): - r""" - Return the minimal orthogonal idempotents of ``self``. - - INPUT:: - - - ``self`` a commutative semisimple algebra - - OUTPUT:: - - - list of idempotents of ``self`` - - EXAMPLES:: - - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: orth = Z5.orthogonal_idempotents() - sage: orth = Z5.orthogonal_idempotents() - sage: sorted(orth, key=str) - [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + - 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + 1/30*B[3] - + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - 1/10*B[2] + 1/20*B[6], - 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - - 1/24*B[5], 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - - 1/24*B[4] + 1/24*B[5]] - sage: orth[2] * orth[4] - 0 - sage: orth[1] ** 2 == orth[1] - True - """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in - self._semi_simple_commutative_decomposition_generators()] + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + + class WithBasis(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def orthogonal_idempotents(self): + r""" + Return a maximal list of orthogonal idempotents of ``self``. + + INPUT: + + - ``self`` -- semisimple algebra + + EXAMPLES:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: orth3 = A3.orthogonal_idempotents() + sage: sorted(orth3, key=str) + [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], + 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + + :: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver (containing the arrows a:x->y + and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: sorted(orth, key=str) + [B['x'], B['y']] + """ + Z = self.center() + orth = Z.orthogonal_idempotents() + return [x.lift() for x in orth] + + + class Commutative(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): + r""" + Decompose a commutative finite dimensional semi-simple + algebra ``A`` into a direct sum of simple A-modules. + + INPUT: + + - ``self`` a finite dimensional semisimple commutative + algebra. + + OUTPUT: + + - list of elements of ``self`` each generating a simple + submodule of ``self`` in direct sum with the others. + The list is maximal. + + Return a list of generators of simple A-modules. + + EXAMPLES: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: sorted(gens, key=str) + [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], + B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - + 1/5*B[5], B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + + B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - + 1/4*B[6], B[0] - 1/3*B[2] + 1/6*B[6], B[0] - + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + + 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + + B[6]] + """ + #Terminal case and stuffs + if listGen==None: + listGen = self.basis().list() + if self.dimension() == 1: + if topLevel: + return self.basis().list() + else: + return [x.lift() for x in self.basis()] + + #Searching for a good generator... + res = [] + B = self.basis() + while len(res)<2: + if listGen==[]: + raise Exception("Unable to fully decompose...") + curGen = listGen[ZZ.random_element(len(listGen))] + listGen.remove(curGen) + phi = self.module_morphism(on_basis=lambda i: + curGen*B[i], + codomain=self, + triangular=True) + aMat = phi.matrix(self.base_ring()) + res = aMat.eigenspaces_right() + + #Gotcha! Let's settle the algebra... + + res = [vector_space for _,vector_space in res] + res = [[self.from_vector(vector) for vector in eigenspace.basis()] + for eigenspace in res] + + decomp = [self.submodule(v, + category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] + + #Recursive on decomp + res = [x for space in decomp for x in + space._semi_simple_commutative_decomposition_generators(topLevel=False)] + if topLevel: + return res + else: + return map( lambda x: x.lift(), res) + + @cached_method + def orthogonal_idempotents(self): + r""" + Return the minimal orthogonal idempotents of ``self``. + + INPUT:: + + - ``self`` a commutative semisimple algebra + + OUTPUT:: + + - list of idempotents of ``self`` + + EXAMPLES:: + + sage: G5 = SymmetricGroup(5) + sage: A5 = G5.algebra(QQ) + sage: Z5 = A5.center() + sage: orth = Z5.orthogonal_idempotents() + sage: orth = Z5.orthogonal_idempotents() + sage: sorted(orth, key=str) + [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] + - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + + 1/30*B[3] + - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + + 1/30*B[3] + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - + 1/10*B[2] + 1/20*B[6], 5/24*B[0] + 1/24*B[1] + + 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], + 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - + 1/24*B[4] + 1/24*B[5]] + sage: orth[2] * orth[4] + 0 + sage: orth[1] ** 2 == orth[1] + True + """ + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in + self._semi_simple_commutative_decomposition_generators()] From e93c82b3db68e769b0c8d11b82bf4741e4b4efea Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:08:10 +0200 Subject: [PATCH 120/665] doctest --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 463ea706cdf..68cac4fa00e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -366,7 +366,7 @@ def orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotent() + sage: A.orthogonal_idempotents() [y, x] """ Aquo = self.semisimple_quotient() From c5fca295b8353130f6a588a1531032f337064be6 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 11:34:09 +0200 Subject: [PATCH 121/665] example lift_idempotent --- src/sage/categories/algebras.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index f077b59b246..63f9fd93380 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -128,13 +128,10 @@ def _lift_idempotent(self): EXAMPLES:: - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: Z3 = A3.center() - sage: Z3._refine_category_(SemisimpleAlgebras(QQ)) - sage: orth = Z3.orthogonal_idempotents() - sage: x = orth[2]._lift_idempotent() - sage: x not in Z3 and x in A3 - True + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example().semisimple_quotient() + sage: orth = A.orthogonal_idempotents() + sage: orth[1]._lift_idempotent() + x TODO: better documentation. """ From eca2e12c53e5921410ee08810386054357849e65 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:13:00 +0200 Subject: [PATCH 122/665] Cartan invariant matrix for general finite dimension algebras with basis --- .../finite_dimensional_algebras_with_basis.py | 65 +++++++++++++++++++ src/sage/categories/semisimple_algebras.py | 10 +-- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 68cac4fa00e..7acef30baee 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -16,6 +16,9 @@ from sage.categories.algebras import Algebras from sage.categories.associative_algebras import AssociativeAlgebras from sage.categories.semisimple_algebras import SemisimpleAlgebras +from sage.matrix.constructor import Matrix +from sage.functions.other import sqrt + class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): r""" @@ -351,6 +354,33 @@ def center(self): center.rename("Center of {}".format(self)) return center + def ideal(self, a, side='left'): + r""" + Construct the ``left`` or ``right`` A-module generated by ``a``. + + EXAMPLE:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.ideal(A.an_element()) + Free module generated by {0, 1, 2, 3} over Rational Field + + """ + B = self.basis() + if side == 'left': + phi = self.module_morphism(on_basis=lambda i: a*B[i], + codomain=self, + triangular=True) + elif side == 'right': + phi = self.module_morphism(on_basis=lambda i: B[i]*a, + codomain=self, + triangluar=True) + else: + raise Exception("Side must be ``left`` or ``right``") + ideal = phi.matrix().image() + #now let's make it a submodule of A + return self.submodule([self.from_vector(v) for v in ideal.basis()], + already_echelonized=True) + def orthogonal_idempotents(self): r""" Return a maximal family of orthogonal idempotents of ``self``. @@ -373,6 +403,41 @@ def orthogonal_idempotents(self): orth_quo = Aquo.orthogonal_idempotents() return [x._lift_idempotent() for x in orth_quo] + @cached_method + def cartan_invariant_matrix(self, side='left'): + r""" + Return the Cartan invariant matrix of the algebra ``self``. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.cartan_invariant_matrix() + [1 0] + [2 1] + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: A3.cartan_invariant_matrix() + [1 0 0] + [0 1 0] + [0 0 1] + + """ + Aquo = self.semisimple_quotient() + orth_quo = Aquo.orthogonal_idempotents() + # Dimension of simple modules + dimSimples = [sqrt(Aquo.ideal(e, side).dimension()) for e in + orth_quo] + orth = [x._lift_idempotent() for x in orth_quo] + return Matrix(self.base_ring(), + len(orth), + lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + + def _cartan_matrix_coef(self, ei, ej): + B = self.basis() + phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, + codomain=self, + triangular=True) + return phi.matrix().rank() + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 019f746455a..a1d317610dd 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -179,7 +179,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev return map( lambda x: x.lift(), res) @cached_method - def orthogonal_idempotents(self): + def orthogonal_idempotents(self, dimSimple=False): r""" Return the minimal orthogonal idempotents of ``self``. @@ -193,11 +193,9 @@ def orthogonal_idempotents(self): EXAMPLES:: - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) + sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() sage: orth = Z5.orthogonal_idempotents() - sage: orth = Z5.orthogonal_idempotents() sage: sorted(orth, key=str) [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] @@ -215,6 +213,4 @@ def orthogonal_idempotents(self): sage: orth[1] ** 2 == orth[1] True """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in - self._semi_simple_commutative_decomposition_generators()] + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] From 3f424921c4924027661c8364f91096d4886e5f33 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:35:59 +0200 Subject: [PATCH 123/665] projective modules --- .../finite_dimensional_algebras_with_basis.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 7acef30baee..7e33a1b7656 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -431,6 +431,22 @@ def cartan_invariant_matrix(self, side='left'): len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + def projective_modules(self, side='left'): + r""" + Return the list of indecomposable projective ``side``-sided + ``self``-modules. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: projs = A.projective_modules() + sage: sorted(projs, key=str) + [Free module generated by {0, 1, 2} over Rational Field, + Free module generated by {0} over Rational Field] + """ + return [self.ideal(e, side) for e in self.orthogonal_idempotents()] + + def _cartan_matrix_coef(self, ei, ej): B = self.basis() phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, From 8dce5116c23d04f9daeddef8b65b3e89cd9551c5 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 29 Aug 2014 12:53:20 +0200 Subject: [PATCH 124/665] projective decomposition --- .../finite_dimensional_algebras_with_basis.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 7e33a1b7656..75792d3349b 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -431,7 +431,7 @@ def cartan_invariant_matrix(self, side='left'): len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) - def projective_modules(self, side='left'): + def projective_decomposition(self, side='left'): r""" Return the list of indecomposable projective ``side``-sided ``self``-modules. @@ -439,10 +439,17 @@ def projective_modules(self, side='left'): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_modules() + sage: projs = A.projective_decomposition() sage: sorted(projs, key=str) [Free module generated by {0, 1, 2} over Rational Field, Free module generated by {0} over Rational Field] + + We check that the sum of the dimensions of the indecomposable + projective module is the dimension of ``self``: + + sage: sum([P.dimension() for P in projs]) == A.dimension() + True + """ return [self.ideal(e, side) for e in self.orthogonal_idempotents()] From f5ad94054c8269611f33e89f42da7c3368e5bd87 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 18:14:26 +0200 Subject: [PATCH 125/665] 16659: renamed, moved some methods to better places --- src/sage/categories/algebras.py | 25 ------- .../finite_dimensional_algebras_with_basis.py | 69 ++++++++++++++++--- src/sage/categories/semisimple_algebras.py | 14 ++-- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 63f9fd93380..a3d296f5b35 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -119,31 +119,6 @@ def _div_(self, y): class Quotients(QuotientsCategory): - class ElementMethods: - - def _lift_idempotent(self): - r""" - Lift an idempotent of parent of ``self`` into an indempotent of - parent of ``self.lift()`` - - EXAMPLES:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example().semisimple_quotient() - sage: orth = A.orthogonal_idempotents() - sage: orth[1]._lift_idempotent() - x - - TODO: better documentation. - """ - idempOld = None - idemp = self.lift() - p = idemp.parent() - while idemp <> idempOld: - tmp = idemp - idemp = (p.one() - (p.one() - idemp**2)**2) - idempOld = tmp - return idemp - class ParentMethods: def algebra_generators(self): diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 75792d3349b..42b05ff6430 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -151,7 +151,7 @@ def radical_basis(self, cache_products=True): from sage.modules.free_module_element import vector if self in SemisimpleAlgebras(self.base_ring()): - return self.from_vector(vector(self.zero())) + return [] if cache_products is True: product_on_basis = cached_function(self.product_on_basis) @@ -354,14 +354,14 @@ def center(self): center.rename("Center of {}".format(self)) return center - def ideal(self, a, side='left'): + def principal_ideal(self, a, side='left'): r""" - Construct the ``left`` or ``right`` A-module generated by ``a``. + Construct the ``side`` A-module generated by ``a``. EXAMPLE:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.ideal(A.an_element()) + sage: A.principal_ideal(A.an_element()) Free module generated by {0, 1, 2, 3} over Rational Field """ @@ -396,12 +396,50 @@ def orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents() - [y, x] + sage: sorted(A.orthogonal_idempotents(), key=str) + [x, y] + sage: Monoids().Finite().example() + An example of a finite multiplicative monoid: the integers + modulo 12 + sage: Z12 = Monoids().Finite().example() + sage: A = Z12.algebra(QQ) + sage: sorted(A.orthogonal_idempotents(), key=str) + [-1/2*B[3] + 1/2*B[9], -1/2*B[8] + 1/2*B[4], -B[0] + 1/2*B[3] + + 1/2*B[9], 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/2*B[3] + + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/4*B[1] + 1/4*B[11] + - 1/4*B[5] - 1/4*B[7], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + + 1/2*B[8] - 1/4*B[11], B[0], B[0] + 1/4*B[1] - 1/2*B[3] - + 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + + 1/4*B[11]] + + """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() - return [x._lift_idempotent() for x in orth_quo] + return [self._lift_idempotent(x) for x in orth_quo] + + def _lift_idempotent(self, x): + r""" + Lift an idempotent of the semisimple quotient of ``self`` into an + idempotent of ``self``. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: Aquo = A.semisimple_quotient() + sage: orth = Aquo.orthogonal_idempotents() + sage: A._lift_idempotent(orth[1]) + y + """ + idempOld = None + assert x in self.semisimple_quotient() + idemp = x.lift() + p = idemp.parent() + while idemp <> idempOld: + tmp = idemp + idemp = (p.one() - (p.one() - idemp**2)**2) + idempOld = tmp + return idemp @cached_method def cartan_invariant_matrix(self, side='left'): @@ -419,12 +457,23 @@ def cartan_invariant_matrix(self, side='left'): [1 0 0] [0 1 0] [0 0 1] - + sage: Z12 = Monoids().Finite().example() + sage: A = Z12.algebra(QQ) + sage: A.cartan_invariant_matrix() + [1 0 0 0 0 0 0 0 0] + [0 1 0 0 0 0 0 0 0] + [0 0 2 0 0 0 0 0 0] + [0 0 0 1 0 0 0 0 0] + [0 0 0 0 1 0 0 0 0] + [0 0 0 0 0 2 0 0 0] + [0 0 0 0 0 0 1 0 0] + [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 0 2] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() # Dimension of simple modules - dimSimples = [sqrt(Aquo.ideal(e, side).dimension()) for e in + dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] orth = [x._lift_idempotent() for x in orth_quo] return Matrix(self.base_ring(), @@ -451,7 +500,7 @@ def projective_decomposition(self, side='left'): True """ - return [self.ideal(e, side) for e in self.orthogonal_idempotents()] + return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents()] def _cartan_matrix_coef(self, ei, ej): diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index a1d317610dd..9654626a51c 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -93,9 +93,8 @@ def orthogonal_idempotents(self): sage: sorted(orth, key=str) [B['x'], B['y']] """ - Z = self.center() - orth = Z.orthogonal_idempotents() - return [x.lift() for x in orth] + return [x.lift() + for x in self.center().orthogonal_idempotents()] class Commutative(CategoryWithAxiom_over_base_ring): @@ -103,7 +102,7 @@ class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLevel=True): + def _orthogonal_decomposition(self, listGen=None, topLevel=True): r""" Decompose a commutative finite dimensional semi-simple algebra ``A`` into a direct sum of simple A-modules. @@ -126,7 +125,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: gens = Z5._semi_simple_commutative_decomposition_generators() + sage: gens = Z5._orthogonal_decomposition() sage: sorted(gens, key=str) [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - @@ -172,7 +171,7 @@ def _semi_simple_commutative_decomposition_generators(self, listGen=None, topLev #Recursive on decomp res = [x for space in decomp for x in - space._semi_simple_commutative_decomposition_generators(topLevel=False)] + space._orthogonal_decomposition(topLevel=False)] if topLevel: return res else: @@ -213,4 +212,5 @@ def orthogonal_idempotents(self, dimSimple=False): sage: orth[1] ** 2 == orth[1] True """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for e in self._semi_simple_commutative_decomposition_generators()] + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for + e in self._orthogonal_decomposition()] From 8e37421fcedf969b42f94078450e4bd7bcf7207f Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 1 Sep 2014 19:12:42 +0200 Subject: [PATCH 126/665] typos --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 42b05ff6430..632641c9b80 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -475,7 +475,7 @@ def cartan_invariant_matrix(self, side='left'): # Dimension of simple modules dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] - orth = [x._lift_idempotent() for x in orth_quo] + orth = [self._lift_idempotent(x) for x in orth_quo] return Matrix(self.base_ring(), len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) From c9d52a81f1e973f9723ca93e0b6bc0c1174c192a Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 3 Sep 2014 15:27:03 +0200 Subject: [PATCH 127/665] undo a stupid error in finite_dimensional_modules_with_basis.matrix --- src/sage/categories/finite_dimensional_modules_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 7a045b21fb9..65f10177f82 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -273,7 +273,7 @@ def matrix(self, base_ring=None, side="left"): if base_ring is None: base_ring = self.codomain().base_ring() - on_basis = self.on_basis + on_basis = self.on_basis() basis_keys = self.domain().basis().keys() m = matrix(base_ring, [on_basis(x).to_vector() for x in basis_keys]) From 3d93d312052666fe553ccf82713817b05ee61b2f Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 09:31:06 +0200 Subject: [PATCH 128/665] 16659: took off randomness, doctest --- .../finite_dimensional_algebras_with_basis.py | 46 +++++++------- src/sage/categories/semisimple_algebras.py | 63 +++++++++---------- 2 files changed, 50 insertions(+), 59 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 632641c9b80..6dcab62f944 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -392,27 +392,24 @@ def orthogonal_idempotents(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field - sage: sorted(A.orthogonal_idempotents(), key=str) - [x, y] - sage: Monoids().Finite().example() + and b:x->y) over Rational Field + sage: A.orthogonal_idempotents() + [y, x] + sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 - sage: Z12 = Monoids().Finite().example() sage: A = Z12.algebra(QQ) - sage: sorted(A.orthogonal_idempotents(), key=str) - [-1/2*B[3] + 1/2*B[9], -1/2*B[8] + 1/2*B[4], -B[0] + 1/2*B[3] + - 1/2*B[9], 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/2*B[3] + - 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/4*B[1] + 1/4*B[11] - - 1/4*B[5] - 1/4*B[7], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] - + 1/2*B[8] - 1/4*B[11], B[0], B[0] + 1/4*B[1] - 1/2*B[3] - - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + - 1/4*B[11]] - - + sage: A.orthogonal_idempotents() + [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - + 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], + 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - + 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - + 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + + 1/4*B[11]] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.orthogonal_idempotents() @@ -429,7 +426,7 @@ def _lift_idempotent(self, x): sage: Aquo = A.semisimple_quotient() sage: orth = Aquo.orthogonal_idempotents() sage: A._lift_idempotent(orth[1]) - y + x """ idempOld = None assert x in self.semisimple_quotient() @@ -461,13 +458,13 @@ def cartan_invariant_matrix(self, side='left'): sage: A = Z12.algebra(QQ) sage: A.cartan_invariant_matrix() [1 0 0 0 0 0 0 0 0] - [0 1 0 0 0 0 0 0 0] - [0 0 2 0 0 0 0 0 0] + [0 2 0 0 0 0 0 0 0] + [0 0 1 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0 0] - [0 0 0 0 0 2 0 0 0] + [0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 1 0 0] - [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 2 0] [0 0 0 0 0 0 0 0 2] """ Aquo = self.semisimple_quotient() @@ -488,10 +485,9 @@ def projective_decomposition(self, side='left'): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_decomposition() - sage: sorted(projs, key=str) - [Free module generated by {0, 1, 2} over Rational Field, - Free module generated by {0} over Rational Field] + sage: projs = A.projective_decomposition(); projs + [Free module generated by {0} over Rational Field, + Free module generated by {0, 1, 2} over Rational Field] We check that the sum of the dimensions of the indecomposable projective module is the dimension of ``self``: diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 9654626a51c..d4e3f92ec2f 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -75,12 +75,12 @@ def orthogonal_idempotents(self): EXAMPLES:: sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: orth3 = A3.orthogonal_idempotents() - sage: sorted(orth3, key=str) - [1/6*B[()] + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + - 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - 1/6*B[(1,3)], - 2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)]] + sage: A3.orthogonal_idempotents() + [2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)], 1/6*B[()] + + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + + 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] + - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - + 1/6*B[(1,3)]] :: @@ -89,9 +89,8 @@ def orthogonal_idempotents(self): algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.orthogonal_idempotents() - sage: sorted(orth, key=str) - [B['x'], B['y']] + sage: Aquo.orthogonal_idempotents() + [B['y'], B['x']] """ return [x.lift() for x in self.center().orthogonal_idempotents()] @@ -125,19 +124,17 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) sage: Z5 = A5.center() - sage: gens = Z5._orthogonal_decomposition() - sage: sorted(gens, key=str) - [B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], - B[0] + 1/5*B[1] + 1/5*B[2] - 1/5*B[3] + 1/5*B[4] - - 1/5*B[5], B[0] + B[1] + B[2] + B[3] + B[4] + B[5] + - B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - - 1/4*B[6], B[0] - 1/3*B[2] + 1/6*B[6], B[0] - - 1/5*B[1] + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + - 1/5*B[5], B[0] - B[1] + B[2] + B[3] - B[4] - B[5] + - B[6]] + sage: Z5._orthogonal_decomposition() + [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + + B[3] + B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] + - B[4] - B[5] + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - + 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] - 1/5*B[1] + + 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + 1/5*B[5], B[0] + + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] - + 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] """ #Terminal case and stuffs - if listGen==None: + if listGen == None: listGen = self.basis().list() if self.dimension() == 1: if topLevel: @@ -151,8 +148,7 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): while len(res)<2: if listGen==[]: raise Exception("Unable to fully decompose...") - curGen = listGen[ZZ.random_element(len(listGen))] - listGen.remove(curGen) + curGen = listGen.pop() phi = self.module_morphism(on_basis=lambda i: curGen*B[i], codomain=self, @@ -195,18 +191,17 @@ def orthogonal_idempotents(self, dimSimple=False): sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() sage: orth = Z5.orthogonal_idempotents() - sage: sorted(orth, key=str) - [1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - - 1/120*B[5] + 1/120*B[6], 2/15*B[0] + 1/15*B[1] + - 1/30*B[3] - - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + - 1/30*B[3] + 1/30*B[4] - 1/30*B[6], 3/10*B[0] - - 1/10*B[2] + 1/20*B[6], 5/24*B[0] + 1/24*B[1] + - 1/24*B[2] - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], - 5/24*B[0] - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - - 1/24*B[4] + 1/24*B[5]] + sage: orth + [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - 1/120*B[1] + + 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - 1/120*B[5] + + 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - + 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - + 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + + 1/24*B[5], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - + 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] sage: orth[2] * orth[4] 0 sage: orth[1] ** 2 == orth[1] From bab79b2d4414e9a1db9daa65176acdfbdbf444df Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 09:35:58 +0200 Subject: [PATCH 129/665] 16659: typo + todo --- src/sage/categories/semisimple_algebras.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index d4e3f92ec2f..25aee74a6e8 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -119,7 +119,7 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): Return a list of generators of simple A-modules. - EXAMPLES: + EXAMPLES:: sage: G5 = SymmetricGroup(5) sage: A5 = G5.algebra(QQ) @@ -132,6 +132,11 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + 1/5*B[5], B[0] + 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] + + .. TODO:: + + Improve the function by only using matrix + operations. """ #Terminal case and stuffs if listGen == None: From c7b81ec0489d33d4c38d0c7ccb9ea92296432ace Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 5 Sep 2014 18:35:01 +0200 Subject: [PATCH 130/665] 16659: Speedup radical_basis --- .../finite_dimensional_algebras_with_basis.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6dcab62f944..91c28a8350e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -159,11 +159,23 @@ def radical_basis(self, cache_products=True): product_on_basis = self.product_on_basis if p == 0: - keys = self.basis().keys() - mat = matrix(self.base_ring(), [ - [sum(product_on_basis(x,j).coefficient(i) * product_on_basis(y,i).coefficient(j) - for i in keys for j in keys) for x in keys] for y in keys - ]) + keys = list(self.basis().keys()) + # x[i,j] = product_on_basis(x,i).coefficient(j) + cache = [{(i,j): c + for i in keys + for j,c in product_on_basis(y,i)} + for y in keys] + mat = [ + [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) + for x in cache] + for y in cache] + + mat = matrix(self.base_ring(), mat) + # Old algorithm: + # mat = matrix(self.base_ring(), [ + # [sum(product_on_basis(x,j).coefficient(i) * c + # for i in keys for j,c in product_on_basis(y,i)) for x in keys] + # for y in keys ]) rad_basis = mat.kernel().basis() else: # TODO: some finite field elements in Sage have both an From 3379d1753b45a33c6e75b07eee6e13177635f1e1 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 13 Mar 2015 00:01:43 -0700 Subject: [PATCH 131/665] Added more methods for root lattices. --- .../root_system/root_lattice_realizations.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 4446b4eea16..63f56e90055 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -3535,6 +3535,74 @@ def smaller(self): """ return [x for x in TransitiveIdeal(attrcall('pred'), [self])] + def extraspecial_pair(self): + r""" + Return the extraspecial pair of ``self`` under the ordering + defined by + :meth:`~sage.combinat.root_system.root_lattice_realizations.RootLatticeRealizations.ParentMethods.positive_roots_by_height`. + + The *extraspecial pair* of a positive root `\gamma` with some total + ordering `<` of the root lattice that respects height is the pair + of positive roots `(\alpha, \beta)` such that `\gamma = \alpha + + \beta` and `\alpha` is as small as possible. + + EXAMPLES:: + + sage: Q = RootSystem(['G', 2]).root_lattice() + sage: Q.highest_root().extraspecial_pair() + (alpha[2], 3*alpha[1] + alpha[2]) + """ + if self.is_positive_root(): + r = self + else: + r = -self + p_roots = self.parent().positive_roots_by_height() + # We won't need any roots higher than us + p_roots = p_roots[:p_roots.index(r)] + for i,a in enumerate(p_roots): + for b in p_roots[i+1:]: + if a + b == r: + return (a, b) + raise ValueError("Unable to find an extraspecial pair") + + def height(self): + r""" + Return the hieght of ``self``. + + The height of a root `\alpha = \sum_i a_i \alpha_i` is defined + to be `h(\alpha) := \sum_i a_i`. + + EXAMPLES:: + + sage: Q = RootSystem(['G', 2]).root_lattice() + sage: Q.highest_root().height() + 5 + """ + return sum(self.coefficients()) + + def norm_squared(self): + r""" + Return the norm squared of ``self``. + + Given a root `\alpha \in \Phi`, we define + + .. MATH:: + + \lVert\alpha\rVert^2 = (\alpha, \alpha) = \sum_{\beta\in\Phi} + \lvert\langle \alpha, \beta^{\vee} \rangle\rvert^2 + + where `(\alpha, \beta)` can be though of as the usual Euclidean + inner product in the ambient space. + + EXAMPLES:: + + sage: Q = RootSystem(['G', 2]).root_lattice() + sage: Q.highest_root().norm_squared() + 48 + """ + L = self.parent().root_system.ambient_space() + return L(self).scalar(L(self)) + ########################################################################## # Level ########################################################################## From ac24f99161a1a2f4c34e3d4eed2d7b3ad705f12c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sat, 14 Mar 2015 14:36:36 -0700 Subject: [PATCH 132/665] 11111: trivial category update in doctest --- src/sage/combinat/sf/k_dual.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index cfe5b1cfd61..0e21f803443 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -483,7 +483,9 @@ def super_categories(self): sage: Q = Sym.kBoundedQuotient(3,t=1) sage: KQB = KBoundedQuotientBases(Q) sage: KQB.super_categories() - [Category of realizations of 3-Bounded Quotient of Symmetric Functions over Univariate Polynomial Ring in t over Rational Field with t=1, Join of Category of graded hopf algebras with basis over Univariate Polynomial Ring in t over Rational Field and Category of subquotients of monoids and Category of quotients of semigroups] + [Category of realizations of 3-Bounded Quotient of Symmetric Functions over Univariate Polynomial Ring in t over Rational Field with t=1, + Join of Category of graded hopf algebras with basis over Univariate Polynomial Ring in t over Rational Field and + Category of quotients of algebras over Univariate Polynomial Ring in t over Rational Field] """ R = self.base().base_ring() category = GradedHopfAlgebrasWithBasis(R) From 50b818d619b01e24330d87c1562356e5e62c6b77 Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Sun, 15 Mar 2015 21:50:06 +0100 Subject: [PATCH 133/665] Fix sublinking --- src/sage/coding/binary_code.pyx | 1 + src/sage/ext/memory.pyx | 1 + src/sage/graphs/asteroidal_triples.pyx | 1 + src/sage/graphs/graph_decompositions/vertex_separation.pyx | 1 + src/sage/graphs/graph_generators_pyx.pyx | 1 + 5 files changed, 5 insertions(+) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index d8a595f62e9..6feecfcaf1a 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp """ Fast binary code routines. diff --git a/src/sage/ext/memory.pyx b/src/sage/ext/memory.pyx index 674b18455f5..b5cf4004e6f 100644 --- a/src/sage/ext/memory.pyx +++ b/src/sage/ext/memory.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp """ Low-level memory allocation functions diff --git a/src/sage/graphs/asteroidal_triples.pyx b/src/sage/graphs/asteroidal_triples.pyx index 260abe307c0..3f106467ecb 100644 --- a/src/sage/graphs/asteroidal_triples.pyx +++ b/src/sage/graphs/asteroidal_triples.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp r""" Asteroidal triples diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index 1ffd4228cc2..e4fa037f404 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp r""" Vertex separation diff --git a/src/sage/graphs/graph_generators_pyx.pyx b/src/sage/graphs/graph_generators_pyx.pyx index ba9dfe8281c..19b2d720ecf 100644 --- a/src/sage/graphs/graph_generators_pyx.pyx +++ b/src/sage/graphs/graph_generators_pyx.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp r""" Common graphs and digraphs generators (Cython) From 52d8a59fbfc23d58f65cd942b0361ac2cf4f767f Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 16 Mar 2015 13:43:40 +0100 Subject: [PATCH 134/665] Trac 17964: fix crash caused by asymmetric rChangeCurrRing() --- .../polynomial/multi_polynomial_libsingular.pyx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index b0d4d9a2108..e35903ff380 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -731,6 +731,17 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): sage: R(2^31) 2 + Check that :trac:`17964` is fixed:: + + sage: K. = QuadraticField(17) + sage: Q. = K[] + sage: f = (-3*a)*y + (5*a) + sage: p = K.primes_above(5)[0] + sage: R = K.residue_field(p) + sage: S = R['x','y'] + sage: S(f) + (2*abar)*y + """ cdef poly *_p cdef poly *mon @@ -850,7 +861,6 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): El_base = El_parent._base while El_poly: - rChangeCurrRing(El_ring) c = si2sa(p_GetCoeff(El_poly, El_ring), El_ring, El_base) try: c = K(c) @@ -858,7 +868,6 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): p_Delete(&_p, _ring) raise if c: - rChangeCurrRing(_ring) mon = p_Init(_ring) p_SetCoeff(mon, sa2si(c, _ring), _ring) for j from 1 <= j <= El_ring.N: From ab180624f535bd09d89047ad607412259aa3ca42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 16 Mar 2015 15:11:47 -0700 Subject: [PATCH 135/665] 11111: axiom-like syntax for Semisimple + minor spacing fixes --- src/sage/categories/algebras.py | 22 ++++++++++++++++++++++ src/sage/categories/semisimple_algebras.py | 19 ++++++++++++++----- src/sage/categories/sets_cat.py | 22 +++++++++++----------- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 5c9f6463ddc..fe855a5330d 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -88,9 +88,31 @@ def __contains__(self, x): # R = self.base_ring() # return [Rings()] # TODO: won't be needed when Rings() will be Rngs().Unital() + class SubcategoryMethods: + def Semisimple(self): + """ + Return the subcategory of semisimple objects of ``self``. + + .. NOTE:: + + This mimics the syntax of axioms for a smooth + transition if ``Semisimple`` becomes one. + + EXAMPLES:: + + sage: Algebras(QQ).SemiSimple() + Category of semisimple algebras over Rational Field + sage: Algebras(QQ).WithBasis().FiniteDimensional().SemiSimple() + Category of finite dimensional semisimple algebras with basis over Rational Field + """ + from sage.categories.semisimple_algebras import SemisimpleAlgebras + return self & SemisimpleAlgebras(self.base_ring()) + Commutative = LazyImport('sage.categories.commutative_algebras', 'CommutativeAlgebras', at_startup=True) Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras') WithBasis = LazyImport('sage.categories.algebras_with_basis', 'AlgebrasWithBasis') + #if/when Semisimple becomes an axiom + #Semisimple = LazyImport('sage.categories.semisimple_algebras', 'SemisimpleAlgebras') class ElementMethods: # TODO: move the content of AlgebraElement here or higher in the category hierarchy diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index f657c2f587e..363f1587f30 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -19,9 +19,18 @@ class SemisimpleAlgebras(Category_over_base_ring): EXAMPLES:: - sage: SemisimpleAlgebras(QQ) + from sage.categories.semisimple_algebras import SemisimpleAlgebras + sage: C = SemisimpleAlgebras(QQ); C Category of semisimple algebras over Rational Field - sage: SemisimpleAlgebras(QQ).super_categories() + + This category is best constructed as:: + + sage: D = Algebras(QQ).Semisimple(); D + Category of semisimple algebras over Rational Field + sage: D is C + True + + sage: C.super_categories() [Category of algebras over Rational Field] Typically, finite group algebras are semisimple:: @@ -34,14 +43,14 @@ class SemisimpleAlgebras(Category_over_base_ring): sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras False - sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras # todo: not implemented + sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras True - .. seealso:: ``_ + .. SEEALSO:: ``_ TESTS:: - sage: TestSuite(SemisimpleAlgebras(QQ)).run() + sage: TestSuite(C).run() """ @cached_method def super_categories(self): diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index b07e20a64cf..b041d40162b 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1402,7 +1402,7 @@ def cartesian_product(*parents): parents, category = cartesian_product.category_from_parents(parents)) - def algebra(self, base_ring, category = None): + def algebra(self, base_ring, category=None): """ Return the algebra of ``self`` over ``base_ring``. @@ -1459,7 +1459,7 @@ def algebra(self, base_ring, category = None): One may specify for which category one takes the algebra:: - sage: A = S.algebra(QQ, category = Sets()); A + sage: A = S.algebra(QQ, category=Sets()); A Free module generated by General Linear Group of degree 4 over Rational Field over Rational Field sage: A.category() Category of set algebras over Rational Field @@ -1490,16 +1490,16 @@ def algebra(self, base_ring, category = None): ... TypeError: `S = Ring of integers modulo 3` is both an additive and a multiplicative semigroup. Constructing its algebra is ambiguous. - Please use, e.g., S.algebra(QQ, category = Semigroups()) + Please use, e.g., S.algebra(QQ, category=Semigroups()) The ambiguity can be resolved using the ``category`` argument:: - sage: A = Z3.algebra(QQ, category = Monoids()); A + sage: A = Z3.algebra(QQ, category=Monoids()); A Free module generated by Ring of integers modulo 3 over Rational Field sage: A.category() Category of finite dimensional monoid algebras over Rational Field - sage: A = Z3.algebra(QQ, category = CommutativeAdditiveGroups()); A + sage: A = Z3.algebra(QQ, category=CommutativeAdditiveGroups()); A Free module generated by Ring of integers modulo 3 over Rational Field sage: A.category() Category of finite dimensional commutative additive group algebras over Rational Field @@ -1531,20 +1531,20 @@ def algebra(self, base_ring, category = None): raise TypeError( """ `S = {}` is both an additive and a multiplicative semigroup. Constructing its algebra is ambiguous. -Please use, e.g., S.algebra(QQ, category = Semigroups())""".format(self)) +Please use, e.g., S.algebra(QQ, category=Semigroups())""".format(self)) from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.groups import Groups from sage.categories.fields import Fields - category = category.Algebras(base_ring) + algebra_category = category.Algebras(base_ring) # Maschke's theorem: under some conditions, the algebra is semisimple # If base_ring is of characteristic 0, this is handled in the FiniteGroups.Algebras category - if self in Groups().Finite() and base_ring in Fields \ + if category.is_subcategory(Groups().Finite()) and base_ring in Fields \ and base_ring.characteristic() > 0 \ and hasattr(self, "cardinality") \ and self.cardinality() % base_ring.characteristic() != 0: - from sage.categories.semisimple_algebras import SemisimpleAlgebras - category = (category, SemisimpleAlgebras(base_ring)) - return CombinatorialFreeModule(base_ring, self, category = category) + algebra_category = algebra_category.Semisimple() + return CombinatorialFreeModule(base_ring, self, + category=algebra_category) class ElementMethods: From 515b0f8673ad51ff588923b062cb5eff3dd7412f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 16 Mar 2015 15:16:16 -0700 Subject: [PATCH 136/665] 11111: removed span method in favor of submodule; use the latter in annihilator; minor doc/formating improvements --- .../finite_dimensional_modules_with_basis.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 65f10177f82..5665e075fc6 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -47,12 +47,6 @@ def vectors_parent(self): """ return self.zero().to_vector().parent() - def span(self, gens, check = True, already_echelonized = False): - return self.vectors_parent().span( - [g.to_vector() for g in gens], - check=check, - already_echelonized = already_echelonized) - def annihilator(self, S, action=operator.mul, side='right', category=None): r""" INPUT: @@ -74,7 +68,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): TODO: double check the convention for ``left/right``. - .. seealso:: :meth:`annihilator_basis` for lots of examples. + .. SEEALSO:: :meth:`annihilator_basis` for lots of examples. EXAMPLES:: @@ -99,7 +93,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): [[Axy, Ay], [Axy, Ax], [Ay, A], [Ax, A]] """ - return self.span(self.annihilator_basis(S, action, side), already_echelonized=True) + return self.submodule(self.annihilator_basis(S, action, side), already_echelonized=True) def annihilator_basis(self, S, action=operator.mul, side='right'): """ @@ -179,7 +173,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): sage: F.annihilator_basis(F.algebra_generators(), action = F.bracket) [x + y] - .. seealso:: :meth:`FiniteAlgebrasWithBasis.ParentMethods.center_basis`. + .. SEEALSO:: :meth:`FiniteAlgebrasWithBasis.ParentMethods.center_basis`. """ # TODO: optimize this! from sage.matrix.constructor import matrix From 9d715e7af3ab99b0b2335b11a23546dd3c1627e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 16 Mar 2015 15:16:45 -0700 Subject: [PATCH 137/665] 11111: doc and formating improvements --- src/sage/categories/modules_with_basis.py | 44 +++++++++------- .../modules/subquotient_module_with_basis.py | 51 +++++++++++++------ 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index e4df904fdff..86676e42646 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -551,16 +551,19 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non - ``gens`` -- a list or family of elements of ``self`` - ``check`` -- (default: True) whether to verify that the elements of ``gens`` are in ``self``. - - ``already_echelonized`` -- (default: False) whether the - elements of gens are already in (not necessarily reduced) - echelon form. + - ``already_echelonized`` -- (default: ``False``) whether + the elements of gens are already in (not necessarily + reduced) echelon form. - If ``already_echelonized`` is False, then the generators - are put in reduced echelon form using :meth:`echelonize`, - and reindexed by `0,1,...`. + If ``already_echelonized`` is ``False``, then the + generators are put in reduced echelon form using + :meth:`echelonize`, and reindexed by `0,1,...`. - .. warning:: at this point, this method only works for - finite dimensional submodules. + .. WARNING:: + + At this point, this method only works for finite + dimensional submodules and if matrices can be + echelonized over the base ring. The basis of the submodule uses the same index set as the generators, and the lifting map sends `y_i` to `gens[i]`. @@ -569,7 +572,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: Y = X.submodule([x[0]-x[1], x[1]-x[2]], already_echelonized = True) + sage: Y = X.submodule([x[0]-x[1], x[1]-x[2]], already_echelonized=True) sage: Y.print_options(prefix='y'); Y Free module generated by {0, 1} over Rational Field sage: y = Y.basis() @@ -593,8 +596,8 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: basis [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] sage: center = S3A.submodule(basis, - ... category = AlgebrasWithBasis(QQ).Subobjects(), - ... already_echelonized = True) + ....: category=AlgebrasWithBasis(QQ).Subobjects(), + ....: already_echelonized=True) sage: center Free module generated by {0, 1, 2} over Rational Field sage: center in Algebras @@ -609,7 +612,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: e.is_idempotent() True - Of course, the center is best constructed using:: + Of course, this center is best constructed using:: sage: center = S3A.center() @@ -621,9 +624,9 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non if not already_echelonized: gens = self.echelonize(gens) from sage.modules.subquotient_module_with_basis import SubModuleWithBasis - return SubModuleWithBasis(gens, ambient=self, category = category) + return SubModuleWithBasis(gens, ambient=self, category=category) - def quotient(self, submodule, check = False, already_echelonized=False, category=None): + def quotient(self, submodule, check=False, already_echelonized=False, category=None): r""" Construct the quotient free module ``self``/``submodule`` @@ -633,13 +636,17 @@ def quotient(self, submodule, check = False, already_echelonized=False, category be turned into one via self.submodule(submodule). - ``check``, ``already_echelonized`` -- passed down to :meth:`submodule`, which see - .. note:: At this point, only free quotients are implemented + .. WARNING:: + + At this point, only quotients of finite dimensional + modules with basis by free submodules with unitriangular + echelon form are supported. EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: Y = X.quotient([x[0]-x[1], x[1]-x[2]], already_echelonized = True) + sage: Y = X.quotient([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() @@ -652,8 +659,9 @@ def quotient(self, submodule, check = False, already_echelonized=False, category """ from sage.modules.subquotient_module_with_basis import SubModuleWithBasis, QuotientModuleWithBasis if not isinstance(submodule, SubModuleWithBasis): - submodule = self.submodule(submodule, check=check, already_echelonized = already_echelonized) - return QuotientModuleWithBasis(submodule, category = category) + submodule = self.submodule(submodule, check=check, + already_echelonized=already_echelonized) + return QuotientModuleWithBasis(submodule, category=category) def tensor(*parents): """ diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index edf8954f85c..853a7275454 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -18,7 +18,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): A class for quotients of a module with basis by a submodule. """ @staticmethod - def __classcall_private__(cls, submodule, category = None): + def __classcall_private__(cls, submodule, category=None): r""" Normalize the input @@ -32,7 +32,8 @@ def __classcall_private__(cls, submodule, category = None): sage: J1 is J2 True """ - category = ModulesWithBasis(submodule.base_ring()).Quotients().or_subcategory(category, join=True) + default_category = ModulesWithBasis(submodule.category().base_ring()).Quotients() + category = default_category.or_subcategory(category, join=True) return super(QuotientModuleWithBasis, cls).__classcall__( cls, submodule, category) @@ -59,11 +60,11 @@ def __init__(self, submodule, category): self._normal = embedding.cokernel_projection() # FIXME: The following currently works only if: # - The ambient space is finite dimensional - # - The embedding is triangular + # - The embedding is unitriangular indices = embedding.cokernel_basis_indices() CombinatorialFreeModule.__init__(self, submodule.base_ring(), indices, - category = category) + category=category) def ambient(self): r""" @@ -80,6 +81,12 @@ def ambient(self): def lift(self, x): """ + Lift ``x`` to the ambient space of ``self``. + + INPUT: + + - ``x`` -- an element of ``self`` + EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() @@ -92,6 +99,12 @@ def lift(self, x): def retract(self, x): r""" + Retract an element of the ambient space by projecting it back to ``self``. + + INPUT: + + - ``x`` -- an element of the ambient space of ``self`` + EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() @@ -114,7 +127,7 @@ class SubModuleWithBasis(CombinatorialFreeModule): """ @staticmethod - def __classcall_private__(cls, basis, ambient = None, category = None, *args, **opts): + def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts): r""" Normalize the input @@ -130,7 +143,8 @@ def __classcall_private__(cls, basis, ambient = None, category = None, *args, ** basis = Family(basis) if ambient is None: ambient = basis.an_element().parent() - category = ModulesWithBasis(ambient.base_ring()).Subobjects().or_subcategory(category, join=True) + 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) @@ -150,18 +164,15 @@ def __init__(self, basis, ambient, category): """ import operator ring = ambient.base_ring() - CombinatorialFreeModule.__init__(self, ring, basis.keys(), category = - category.Subobjects()) + CombinatorialFreeModule.__init__(self, ring, basis.keys(), + category=category.Subobjects()) self._ambient = ambient self._basis = basis self.lift_on_basis = self._basis.__getitem__ - def _inverse_on_support(self, j): - return self._invsup.get(j, None) - def ambient(self): """ - Returns the ambient space of ``self`` + Return the ambient space of ``self``. EXAMPLES:: @@ -175,31 +186,39 @@ def ambient(self): @lazy_attribute def lift(self): r""" - Returns the lift map to the ambient space. + The lift (embedding) map from ``self`` to the ambient space. EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() - sage: [ u.lift() for u in y ] + sage: Y.lift + Generic morphism: + From: Free module generated by {0, 1} over Rational Field + To: Free module generated by {0, 1, 2} over Rational Field + sage: [ Y.lift(u) for u in y ] [B[0] - B[1], B[1] - B[2]] sage: (y[0] + y[1]).lift() B[0] - B[2] """ return self.module_morphism(self.lift_on_basis, codomain=self.ambient(), - triangular="lower", cmp = self.ambient().get_order_cmp(), + triangular="lower", cmp=self.ambient().get_order_cmp(), inverse_on_support="compute") @lazy_attribute def retract(self): r""" - Returns the retract map from the ambient space. + The retract map from the ambient space. EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() + sage: Y.retract + Generic morphism: + From: Free module generated by {0, 1, 2} over Rational Field + To: Free module generated by {0, 1} over Rational Field sage: Y.retract(x[0] - x[2]) B[0] + B[1] From 9081ef8d790f3e4a55cc27b9ad50184a5ac57063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 16 Mar 2015 16:09:53 -0700 Subject: [PATCH 138/665] 11111: is_submodule for submodules with basis --- .../finite_dimensional_modules_with_basis.py | 6 ++-- .../modules/subquotient_module_with_basis.py | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 5665e075fc6..ec00ba140b1 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -80,15 +80,13 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): Basis matrix: [ 1 0 -1/2 -3/2] - Note: currently `A` forgot everything about `F`; its - ambient space is a :class:`FreeModule` of same dimension - as `F`. But one can, for example, compute inclusions:: + Taking annihilator is order reversing for inclusion:: sage: A = F.annihilator([]); A .rename("A") sage: Ax = F.annihilator([x]); Ax .rename("Ax") sage: Ay = F.annihilator([y]); Ay .rename("Ay") sage: Axy = F.annihilator([x,y]); Axy.rename("Axy") - sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_subspace"))) + sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_submodule"))) sage: P.cover_relations() [[Axy, Ay], [Axy, Ax], [Ay, A], [Ax, A]] diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/subquotient_module_with_basis.py index 853a7275454..b9db95760bd 100644 --- a/src/sage/modules/subquotient_module_with_basis.py +++ b/src/sage/modules/subquotient_module_with_basis.py @@ -228,3 +228,37 @@ def retract(self): True """ return self.lift.section() + + def is_submodule(self, other): + """ + Return whether ``self`` is a submodule of ``other``. + + INPUT: + + - ``other`` -- another submodule of the same ambient module, or the ambient module itself + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(4)); x = X.basis() + sage: F = X.submodule([x[0]-x[1], x[1]-x[2], x[2]-x[3]]) + sage: G = X.submodule([x[0]-x[2]]) + sage: H = X.submodule([x[0]-x[1], x[2]]) + sage: F.is_submodule(X) + True + sage: G.is_submodule(F) + True + sage: H.is_submodule(F) + False + """ + if other is self.ambient(): + return True + if not isinstance(self, SubModuleWithBasis) and self.ambient() is other.ambient(): + raise ValueError("other (=%s) should be a submodule of the same ambient space"%other) + if not self in ModulesWithBasis.FiniteDimensional: + raise NotImplementedError("is_submodule for infinite dimensional modules") + for b in self.basis(): + try: + other.retract(b.lift()) + except ValueError: + return False + return True From f8ad2a8af802cbeeebe0b1a65fcd2a12f0582345 Mon Sep 17 00:00:00 2001 From: Josh Swanson Date: Thu, 19 Mar 2015 15:29:22 -0700 Subject: [PATCH 139/665] CombinatorialObject to CloneableList in Tableau --- src/sage/combinat/tableau.py | 48 ++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 590ba751214..95dd1f1f676 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -77,6 +77,7 @@ from sage.structure.element import Element from sage.structure.global_options import GlobalOptions from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.list_clone import ClonableList from sage.structure.parent import Parent from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.decorators import rename_keyword @@ -190,7 +191,7 @@ notation = dict(alt_name="convention") ) -class Tableau(CombinatorialObject, Element): +class Tableau(ClonableList): """ A class to model a tableau. @@ -284,11 +285,6 @@ def __classcall_private__(cls, t): except TypeError: raise ValueError("A tableau must be a list of iterables.") - # and that it has partition shape - from sage.combinat.partition import _Partitions - if not map(len,t) in _Partitions: - raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") - return Tableaux_all().element_class(Tableaux_all(), t) def __init__(self, parent, t): @@ -311,16 +307,48 @@ def __init__(self, parent, t): False """ if isinstance(t, Tableau): - Element.__init__(self, parent) # Since we are (supposed to be) immutable, we can share the underlying data - CombinatorialObject.__init__(self, t._list) + self._list = t + ClonableList.__init__(self, parent, t._list) return # Normalize t to be a list of tuples. t = map(tuple, t) - Element.__init__(self, parent) - CombinatorialObject.__init__(self, t) + self._list = t + ClonableList.__init__(self, parent, t) + + def __eq__(self, other): + if isinstance(other, Tableau): + return self._list.__eq__(other._list) + else: + return self._list.__eq__(other) + + def __ne__(self, other): +# return not self.__eq__(other) + if isinstance(other, Tableau): + return self._list.__ne__(other._list) + else: + return self._list.__ne__(other) + + def check(self): + r""" + Check that ``self`` is a valid straight shape tableau. + + EXAMPLES:: + + sage: t = Tableau([[1,1],[2]]) + sage: t.check() + + sage: t = Tableau([[None, None, 1], [2, 4], [3, 4, 5]]) + Traceback (most recent call last): + ... + ValueError: A tableau must be a list of iterables of weakly decreasing length. + """ + # and that it has partition shape + from sage.combinat.partition import _Partitions + if not map(len, self) in _Partitions: + raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") def __setstate__(self, state): """ From a4f9bdba3125037d8b5217a03274a3a13b59a1c4 Mon Sep 17 00:00:00 2001 From: Josh Swanson Date: Thu, 19 Mar 2015 16:15:39 -0700 Subject: [PATCH 140/665] removed _list --- src/sage/combinat/k_tableau.py | 10 ++++------ src/sage/combinat/tableau.py | 29 ++++++++++++----------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index cd6e98a3955..d443281e144 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -478,7 +478,7 @@ def chi(x): return x return "%s"%x if self.parent()._representation in ['core', 'bounded']: - t = [[chi(x) for x in row] for row in self._list] + t = [[chi(x) for x in row] for row in self] from output import tex_from_array return tex_from_array(t) else: @@ -738,7 +738,6 @@ def __init__(self, parent, t): sage: TestSuite(t).run() """ self.k = parent.k - self._list = [r for r in t] ClonableList.__init__(self, parent, t) def _repr_diagram(self): @@ -821,7 +820,7 @@ def check(self): ... ValueError: The tableau is not semistandard! """ - if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self._list,self.k).weight(): + if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self,self.k).weight(): raise ValueError("The weight of the parent does not agree with the weight of the tableau!") t = SkewTableau(list(self)) if not t in SemistandardSkewTableaux(): @@ -1016,7 +1015,7 @@ def list_of_standard_cells(self): raise ValueError("This method only works for straight tableaux!") if self.weight() not in Partitions(sum(self.weight())): raise ValueError("This method only works for weak tableaux with partition weight!") - if self._list == []: + if not self: return [] mu = Partition(self.weight()).conjugate() already_used = [] @@ -1448,10 +1447,9 @@ def __init__(self, parent, t): """ k = parent.k self.k = k - self._list = [list(r) for r in t] if parent._outer_shape.conjugate().length() > k: raise ValueError("%s is not a %s-bounded tableau"%(t, k)) - ClonableList.__init__(self, parent, self._list) + ClonableList.__init__(self, parent, [list(r) for r in t]) def _repr_diagram(self): r""" diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 95dd1f1f676..045e3423977 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -308,28 +308,25 @@ def __init__(self, parent, t): """ if isinstance(t, Tableau): # Since we are (supposed to be) immutable, we can share the underlying data - self._list = t - ClonableList.__init__(self, parent, t._list) + ClonableList.__init__(self, parent, list(t)) return # Normalize t to be a list of tuples. t = map(tuple, t) - self._list = t ClonableList.__init__(self, parent, t) def __eq__(self, other): if isinstance(other, Tableau): - return self._list.__eq__(other._list) + return list(self).__eq__(list(other)) else: - return self._list.__eq__(other) + return list(self).__eq__(other) def __ne__(self, other): -# return not self.__eq__(other) if isinstance(other, Tableau): - return self._list.__ne__(other._list) + return list(self).__ne__(list(other)) else: - return self._list.__ne__(other) + return list(self).__ne__(other) def check(self): r""" @@ -358,8 +355,6 @@ def __setstate__(self, state): TESTS:: - sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+IL\xcaIM,\xe5\n\x81\xd0\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl![l!;\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x9031\xb14I\x0f\x00\xf6\xae)7') # indirect doctest for unpickling a Tableau_class element - [[1]] sage: loads(dumps( Tableau([[1]]) )) # indirect doctest for unpickling a Tableau element [[1]] """ @@ -400,7 +395,7 @@ def _repr_list(self): sage: T._repr_list() '[[1, 2, 3], [4, 5]]' """ - return repr(map(list, self._list)) + return repr(map(list, self)) # Overwrite the object from CombinatorialObject # until this is no longer around @@ -438,9 +433,9 @@ def _repr_compact(self): sage: Tableau([])._repr_compact() '-' """ - if len(self._list)==0: + if len(self)==0: return '-' - else: return '/'.join(','.join('%s'%r for r in row) for row in self._list) + else: return '/'.join(','.join('%s'%r for r in row) for row in self) def _ascii_art_(self): """ @@ -681,7 +676,7 @@ def __div__(self, t): if not self.shape().contains(t): raise ValueError("the shape of the tableau must contain the partition") - st = [list(row) for row in self._list] # create deep copy of t + st = [list(row) for row in self] # create deep copy of t for i, t_i in enumerate(t): st_i = st[i] @@ -1788,7 +1783,7 @@ def anti_restrict(self, n): sage: t.anti_restrict(5) [[None, None, None], [None, None]] """ - t = [list(row) for row in self._list] # create deep copy of t + t = [list(row) for row in self] # create deep copy of t for row in t: for col in xrange(len(row)): @@ -2017,7 +2012,7 @@ def bump_multiply(left, right): raise TypeError("right must be a Tableau") row = len(right) - product = Tableau([list(a) for a in left._list]) # create deep copy of left + product = Tableau([list(a) for a in left]) # create deep copy of left while row > 0: row -= 1 for i in right[row]: @@ -3558,7 +3553,7 @@ def __init__(self, parent, t): raise ValueError("the entries in each row of a standard tableau must be strictly increasing") # and that the entries are in bijection with {1,2,...,n} - if sorted(flatten(self._list))!=range(1,self.size()+1): + if sorted(flatten(list(self)))!=range(1,self.size()+1): raise ValueError("the entries in a standard tableau must be in bijection with 1,2,...,n") From 10b69240dfceaec610564bb26e2ab7eb1a4a5b45 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Fri, 20 Mar 2015 00:20:27 +0100 Subject: [PATCH 141/665] Add parameter axes_labels_size to Graphics. This allows to set separately the font size of the axes labels and that of the tick marks and fixes the issue reported in track #18004. --- src/sage/plot/graphics.py | 57 ++++++++++++++++++++++++++++++++++----- src/sage/plot/plot.py | 2 ++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 0c8f61abb76..085879c828d 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -11,7 +11,9 @@ - Jeroen Demeyer (2012-04-19): split off this file from plot.py (:trac:`12857`) - Punarbasu Purkayastha (2012-05-20): Add logarithmic scale (:trac:`4529`) -- Emily Chen (2013-01-05): Add documentation for :meth:`~sage.plot.graphics.Graphics.show` figsize parameter (:trac:`5956`) +- Emily Chen (2013-01-05): Add documentation for + :meth:`~sage.plot.graphics.Graphics.show` figsize parameter (:trac:`5956`) +- Eric Gourgoulhon (2015-03-19): Add parameter axes_labels_size (:trac:`18004`) """ @@ -148,6 +150,7 @@ def __init__(self): self._bbox_extra_artists = [] self._extra_kwds = {} self._fontsize = 10 + self._axes_labels_size = 1.7 self._legend_colors = [] self._legend_opts = {} self._objects = [] @@ -470,6 +473,9 @@ def fontsize(self, s=None): """ Set the font size of axes labels and tick marks. + Note that the relative size of the axes labels font w.r.t. the tick + marks font can be adjusted via :meth:`axes_labels_size`. + INPUT: @@ -500,6 +506,40 @@ def fontsize(self, s=None): return self._fontsize self._fontsize = int(s) + def axes_labels_size(self, s=None): + """ + Set the relative size of axes labels w.r.t. the axes tick marks. + + INPUT: + + - ``s`` - float, relative size of axes labels w.r.t. to the tick marks, + the size of the tick marks being set by :meth:`fontsize`. + + If called with no input, return the current relative size. + + EXAMPLES:: + + sage: p = plot(sin(x^2), (x, -3, 3), axes_labels=['$x$','$y$']) + sage: p.axes_labels_size() # default value + 1.7 + sage: p.axes_labels_size(2.5) + sage: p.axes_labels_size() + 2.5 + + Now the axes labels are large w.r.t. the tick marks:: + + sage: p + Graphics object consisting of 1 graphics primitive + + """ + if s is None: + try: + return self._axes_labels_size + except AttributeError: + self._axes_labels_size = 1.7 + return self._axes_labels_size + self._axes_labels_size = float(s) + def axes(self, show=None): """ Set whether or not the `x` and `y` axes are shown @@ -1255,8 +1295,8 @@ def _set_scale(self, figure, scale=None, base=None): # this dictionary to contain the default value for that parameter. SHOW_OPTIONS = dict(# axes options - axes=None, axes_labels=None, axes_pad=None, - base=None, scale=None, + axes=None, axes_labels=None, axes_labels_size=None, + axes_pad=None, base=None, scale=None, xmin=None, xmax=None, ymin=None, ymax=None, # Figure options aspect_ratio=None, dpi=DEFAULT_DPI, fig_tight=True, @@ -1322,6 +1362,10 @@ def show(self, filename=None, linkmode=False, **kwds): strings; the first is used as the label for the horizontal axis, and the second for the vertical axis. + - ``axes_labels_size`` - (default: current setting -- 1.7) scale factor + relating the size of the axes labels with respect to the size of the + tick marks. + - ``fontsize`` - (default: current setting -- 10) positive integer; used for axes labels; if you make this very large, you may have to increase figsize to see all labels. @@ -2362,8 +2406,8 @@ def _get_vmin_vmax(self, vmin, vmax, basev, axes_pad): def matplotlib(self, filename=None, xmin=None, xmax=None, ymin=None, ymax=None, figsize=None, figure=None, sub=None, - axes=None, axes_labels=None, fontsize=None, - frame=False, verify=True, + axes=None, axes_labels=None, axes_labels_size=None, + fontsize=None, frame=False, verify=True, aspect_ratio = None, gridlines=None, gridlinesstyle=None, vgridlinesstyle=None, hgridlinesstyle=None, @@ -2469,6 +2513,7 @@ def matplotlib(self, filename=None, self.fontsize(fontsize) self.axes_labels(l=axes_labels) + self.axes_labels_size(s=axes_labels_size) if figsize is not None and not isinstance(figsize, (list, tuple)): # in this case, figsize is a number and should be positive @@ -2831,7 +2876,7 @@ def matplotlib(self, filename=None, if self._axes_labels is not None: label_options={} label_options['color']=self._axes_label_color - label_options['size']=self._fontsize + label_options['size']=int(self._axes_labels_size * self._fontsize) subplot.set_xlabel(self._axes_labels[0], **label_options) subplot.set_ylabel(self._axes_labels[1], **label_options) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index ccf6ce73f0f..5273c7c15c6 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1104,6 +1104,8 @@ def plot(funcs, *args, **kwds): Graphics object consisting of 1 graphics primitive sage: plot(sin(x^2), (x, -3, 3), title='Plot of sin(x^2)', axes_labels=['x','y']) # These will not Graphics object consisting of 1 graphics primitive + sage: plot(sin(x^2), (x, -3, 3), axes_labels=['x','y'], axes_labels_size=2.5) # Large axes labels (w.r.t. the tick marks) + Graphics object consisting of 1 graphics primitive :: From a59b0f93c35d90776426d74b8033dd6076dd19a4 Mon Sep 17 00:00:00 2001 From: Jan Keitel Date: Thu, 19 Mar 2015 17:08:59 -0700 Subject: [PATCH 142/665] Docstrings for __eq__ and __ne__ --- src/sage/combinat/tableau.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 045e3423977..36ae54fc8b1 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -317,12 +317,48 @@ def __init__(self, parent, t): ClonableList.__init__(self, parent, t) def __eq__(self, other): + r""" + Check whether ``self`` is equal to ``other``. + + TODO: + + This overwrites the equality check of + :class:`sage.structure.list_clone.ClonableList` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + k-tableaux. + + For now, two elements are equal if their underlying + defining lists compare equal. + + INPUT: + + ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A Boolean. + """ if isinstance(other, Tableau): return list(self).__eq__(list(other)) else: return list(self).__eq__(other) def __ne__(self, other): + r""" + Check whether ``self`` is unequal to ``other``. + + See the documentation of :meth:`__eq__`. + + INPUT: + + ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A Boolean. + """ if isinstance(other, Tableau): return list(self).__ne__(list(other)) else: From 77ab5b6ee5f9e27c3636788e1fc7c75df09c33fa Mon Sep 17 00:00:00 2001 From: Jan Keitel Date: Thu, 19 Mar 2015 17:20:33 -0700 Subject: [PATCH 143/665] Remaining docstrings for equality testing. --- src/sage/combinat/tableau.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 36ae54fc8b1..96a328450ab 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -339,6 +339,14 @@ def __eq__(self, other): OUTPUT: A Boolean. + + TESTS:: + + sage: t = Tableau([[1,2]]) + sage: t == Tableau([[2,3]]) + False + sage: t == Tableaux(2)([[1,2]]) + True """ if isinstance(other, Tableau): return list(self).__eq__(list(other)) @@ -358,6 +366,12 @@ def __ne__(self, other): OUTPUT: A Boolean. + + TESTS:: + + sage: t = Tableau([[2,3],[1]]) + sage: t != [] + True """ if isinstance(other, Tableau): return list(self).__ne__(list(other)) From 1ade1cc9b92893309035a455e7220b08bf9919b4 Mon Sep 17 00:00:00 2001 From: Jan Keitel Date: Thu, 19 Mar 2015 17:26:39 -0700 Subject: [PATCH 144/665] One more addition to the equality testing --- src/sage/combinat/tableau.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 96a328450ab..f15a1ceb66e 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -343,15 +343,15 @@ def __eq__(self, other): TESTS:: sage: t = Tableau([[1,2]]) - sage: t == Tableau([[2,3]]) + sage: t == 0 False sage: t == Tableaux(2)([[1,2]]) True """ if isinstance(other, Tableau): - return list(self).__eq__(list(other)) + return list(self) == list(other) else: - return list(self).__eq__(other) + return list(self) == other def __ne__(self, other): r""" @@ -374,9 +374,9 @@ def __ne__(self, other): True """ if isinstance(other, Tableau): - return list(self).__ne__(list(other)) + return list(self) != list(other) else: - return list(self).__ne__(other) + return list(self) != other def check(self): r""" From 1ffc713eae626876785cf26216f5cbfd37ad7a34 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 19 Mar 2015 18:46:59 -0700 Subject: [PATCH 145/665] 16659: numerous types and refactoring some names --- src/sage/categories/algebras.py | 7 +-- .../finite_dimensional_algebras_with_basis.py | 29 +++++------ src/sage/categories/semisimple_algebras.py | 50 +++++++++---------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 02bbee406a6..01ada27fa94 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -249,9 +249,10 @@ class ElementMethods: def _mul_(self, right): r""" Product of two elements. - INPUT:: - - ``self``, ``right`` -- two elements + INPUT: + + - ``self``, ``right`` -- two elements If B is a SubModuleWithBasis of A, then the multiplication law of B is inherited from the multiplication of A. @@ -264,4 +265,4 @@ def _mul_(self, right): 4*B[2] + 6*B[3] + 5*B[6] """ p = self.parent() - return p.retract( self.lift() * right.lift()) + return p.retract(self.lift() * right.lift()) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 91c28a8350e..71911315452 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -171,11 +171,6 @@ def radical_basis(self, cache_products=True): for y in cache] mat = matrix(self.base_ring(), mat) - # Old algorithm: - # mat = matrix(self.base_ring(), [ - # [sum(product_on_basis(x,j).coefficient(i) * c - # for i in keys for j,c in product_on_basis(y,i)) for x in keys] - # for y in keys ]) rad_basis = mat.kernel().basis() else: # TODO: some finite field elements in Sage have both an @@ -368,7 +363,7 @@ def center(self): def principal_ideal(self, a, side='left'): r""" - Construct the ``side`` A-module generated by ``a``. + Construct the ``side`` `A`-module generated by ``a``. EXAMPLE:: @@ -444,31 +439,31 @@ def _lift_idempotent(self, x): assert x in self.semisimple_quotient() idemp = x.lift() p = idemp.parent() - while idemp <> idempOld: + while idemp != idempOld: tmp = idemp idemp = (p.one() - (p.one() - idemp**2)**2) idempOld = tmp return idemp @cached_method - def cartan_invariant_matrix(self, side='left'): + def cartan_invariants_matrix(self, side='left'): r""" - Return the Cartan invariant matrix of the algebra ``self``. + Return the Cartan invariants matrix of the algebra ``self``. EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.cartan_invariant_matrix() + sage: A.cartan_invariants_matrix() [1 0] [2 1] sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: A3.cartan_invariant_matrix() + sage: A3.cartan_invariants_matrix() [1 0 0] [0 1 0] [0 0 1] sage: Z12 = Monoids().Finite().example() sage: A = Z12.algebra(QQ) - sage: A.cartan_invariant_matrix() + sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0 0] [0 2 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0] @@ -489,15 +484,15 @@ def cartan_invariant_matrix(self, side='left'): len(orth), lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) - def projective_decomposition(self, side='left'): + def projective_indecomposables(self, side='left'): r""" - Return the list of indecomposable projective ``side``-sided + Return the list of indecomposable projective ``side`` ``self``-modules. EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_decomposition(); projs + sage: projs = A.projective_indecomposables(); projs [Free module generated by {0} over Rational Field, Free module generated by {0, 1, 2} over Rational Field] @@ -511,7 +506,7 @@ def projective_decomposition(self, side='left'): return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents()] - def _cartan_matrix_coef(self, ei, ej): + def _cartan_matrix_coeff(self, ei, ej): B = self.basis() phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, codomain=self, @@ -524,7 +519,7 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ Return the matrix of the action of ``self`` on the algebra. - INPUT:: + INPUT: - ``base_ring`` -- the base ring for the matrix to be constructed - ``action`` -- a function (default: :func:`operator.mul`) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index f2acb7fb020..423ea6d4191 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -12,8 +12,6 @@ from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.misc.cachefunc import cached_method from algebras import Algebras -from sage.categories.associative_algebras import AssociativeAlgebras -from sage.rings.integer_ring import ZZ class SemisimpleAlgebras(Category_over_base_ring): @@ -75,7 +73,8 @@ class ParentMethods: @cached_method def orthogonal_idempotents(self): r""" - Return a maximal list of orthogonal idempotents of ``self``. + Return a maximal list of orthogonal idempotents of + ``self``. INPUT: @@ -94,9 +93,9 @@ def orthogonal_idempotents(self): :: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path - algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver (containing + the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() sage: Aquo.orthogonal_idempotents() [B['y'], B['x']] @@ -104,7 +103,6 @@ def orthogonal_idempotents(self): return [x.lift() for x in self.center().orthogonal_idempotents()] - class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -147,8 +145,8 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): Improve the function by only using matrix operations. """ - #Terminal case and stuffs - if listGen == None: + # Terminal case and stuffs + if listGen is None: listGen = self.basis().list() if self.dimension() == 1: if topLevel: @@ -156,11 +154,11 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): else: return [x.lift() for x in self.basis()] - #Searching for a good generator... + # Searching for a good generator... res = [] B = self.basis() - while len(res)<2: - if listGen==[]: + while len(res) < 2: + if listGen == []: raise Exception("Unable to fully decompose...") curGen = listGen.pop() phi = self.module_morphism(on_basis=lambda i: @@ -170,35 +168,37 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): aMat = phi.matrix(self.base_ring()) res = aMat.eigenspaces_right() - #Gotcha! Let's settle the algebra... - - res = [vector_space for _,vector_space in res] - res = [[self.from_vector(vector) for vector in eigenspace.basis()] - for eigenspace in res] - + # Gotcha! Let's settle the algebra... + + res = [vector_space for _, vector_space in res] + res = [[self.from_vector(vector) + for vector in eigenspace.basis()] + for eigenspace in res] + decomp = [self.submodule(v, - category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) for v in res] + category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) + for v in res] - #Recursive on decomp + # Recursive on decomp res = [x for space in decomp for x in space._orthogonal_decomposition(topLevel=False)] if topLevel: return res else: - return map( lambda x: x.lift(), res) + return map(lambda x: x.lift(), res) @cached_method def orthogonal_idempotents(self, dimSimple=False): r""" Return the minimal orthogonal idempotents of ``self``. - INPUT:: + INPUT: - - ``self`` a commutative semisimple algebra + - ``self`` a commutative semisimple algebra - OUTPUT:: + OUTPUT: - - list of idempotents of ``self`` + - list of idempotents of ``self`` EXAMPLES:: From d196cb30e95cf252116237d400c4d29b1d9fbfa9 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Thu, 19 Mar 2015 19:24:54 -0700 Subject: [PATCH 146/665] trivial fixes and iterator for Monoids().Finite().example() --- src/sage/categories/examples/finite_monoids.py | 5 +++++ .../categories/finite_dimensional_algebras_with_basis.py | 2 +- src/sage/categories/semisimple_algebras.py | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index fc5feb28b86..93377696cef 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -139,6 +139,11 @@ def an_element(self): """ return self(ZZ(42) % self.n) + def __iter__(self): + for x in range(self.n): + yield x + return + class Element (ElementWrapper): wrapped_class = Integer diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 71911315452..aef2c3b085a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -482,7 +482,7 @@ def cartan_invariants_matrix(self, side='left'): orth = [self._lift_idempotent(x) for x in orth_quo] return Matrix(self.base_ring(), len(orth), - lambda i,j: self._cartan_matrix_coef(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + lambda i,j: self._cartan_matrix_coeff(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) def projective_indecomposables(self, side='left'): r""" diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 423ea6d4191..e40a846771a 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -101,7 +101,7 @@ def orthogonal_idempotents(self): [B['y'], B['x']] """ return [x.lift() - for x in self.center().orthogonal_idempotents()] + for x in self.center().central_orthogonal_idempotents()] class Commutative(CategoryWithAxiom_over_base_ring): @@ -188,9 +188,9 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): return map(lambda x: x.lift(), res) @cached_method - def orthogonal_idempotents(self, dimSimple=False): + def central_orthogonal_idempotents(self, dimSimple=False): r""" - Return the minimal orthogonal idempotents of ``self``. + Return the minimum set of central orthogonal idempotents of ``self``. INPUT: @@ -204,7 +204,7 @@ def orthogonal_idempotents(self, dimSimple=False): sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() - sage: orth = Z5.orthogonal_idempotents() + sage: orth = Z5.central_orthogonal_idempotents() sage: orth [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + From 2ae528e363c4b279d5e1ac87ef6c2b45785aebcd Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 20 Mar 2015 11:28:59 -0700 Subject: [PATCH 147/665] 16659: Pierce decomposition, some doctest according to #16926 --- .../categories/examples/finite_monoids.py | 7 +- .../finite_dimensional_algebras_with_basis.py | 68 +++++++++++++++++-- src/sage/categories/semisimple_algebras.py | 10 +-- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index 93377696cef..6b66ceebfe3 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -72,7 +72,8 @@ def __init__(self, n = 12): """ self.n = n - Parent.__init__(self, category = Monoids().Finite()) + Parent.__init__(self, category = + Monoids().Finite().FinitelyGenerated()) def _repr_(self): r""" @@ -139,10 +140,6 @@ def an_element(self): """ return self(ZZ(42) % self.n) - def __iter__(self): - for x in range(self.n): - yield x - return class Element (ElementWrapper): wrapped_class = Integer diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index aef2c3b085a..8d9558576d6 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -482,7 +482,8 @@ def cartan_invariants_matrix(self, side='left'): orth = [self._lift_idempotent(x) for x in orth_quo] return Matrix(self.base_ring(), len(orth), - lambda i,j: self._cartan_matrix_coeff(orth[i], orth[j])/(dimSimples[i]*dimSimples[j])) + lambda i,j: self.pierce_decomposition_component(orth[i], + orth[j]).dimension()/(dimSimples[i]*dimSimples[j])) def projective_indecomposables(self, side='left'): r""" @@ -505,13 +506,70 @@ def projective_indecomposables(self, side='left'): """ return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents()] + def pierce_decomposition_component(self, ei, ej): + r""" + Return the Pierce decomposition component of ``self``. + + INPUT: + + - ``self`` -- an algebra `A` + - `e_i` -- an orthogonal idempotent of ``self`` + - `e_j` -- an orthogonal idempotent of ``self`` + + OUTPUT: + + - `e_i A e_j` as a subalgebra of ``self`` - def _cartan_matrix_coeff(self, ei, ej): + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: idemp = A.orthogonal_idempotents() + sage: A.pierce_decomposition_component(idemp[1], idemp[0]) + Free module generated by {0, 1} over Rational Field + sage: A.pierce_decomposition_component(idemp[0], idemp[1]) + Free module generated by {} over Rational Field + + + We can for example recover the unique 2 dimensional representation + of S4:: + + sage: A4 = SymmetricGroup(4).algebra(QQ) + sage: e = A4.orthogonal_idempotents()[2] + sage: A4.pierce_decomposition_component(e, e) + Free module generated by {0, 1, 2, 3} over Rational Field + """ B = self.basis() phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, - codomain=self, - triangular=True) - return phi.matrix().rank() + codomain=self, triangular=True) + ideal = phi.matrix().image() + return self.submodule([self.from_vector(v) for v in ideal.basis()], already_echelonized=True) + + def pierce_decomposition(self): + r""" + Return the Pierce decomposition of ``self`` + + OUTPUT: + + - list of subalgebras `e_i A e_j` for `e_i, e_j` orthogonal + idempotents + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.pierce_decomposition() + [Free module generated by {0} over Rational Field, Free module + generated by {} over Rational Field, Free module generated by + {0, 1} over Rational Field, Free module generated by {0} over + Rational Field] + + """ + import itertools + decomp = [] + for (ei, ej) in itertools.product(self.orthogonal_idempotents(), + repeat=2): + decomp.append(self.pierce_decomposition_component(ei, ej)) + return decomp + class ElementMethods: diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index e40a846771a..bc70c5b0f07 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -84,11 +84,11 @@ def orthogonal_idempotents(self): sage: A3 = SymmetricGroup(3).algebra(QQ) sage: A3.orthogonal_idempotents() - [2/3*B[()] - 1/3*B[(1,2,3)] - 1/3*B[(1,3,2)], 1/6*B[()] - + 1/6*B[(2,3)] + 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + - 1/6*B[(1,3,2)] + 1/6*B[(1,3)], 1/6*B[()] - 1/6*B[(2,3)] - - 1/6*B[(1,2)] + 1/6*B[(1,2,3)] + 1/6*B[(1,3,2)] - - 1/6*B[(1,3)]] + [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), 1/6*() + 1/6*(2,3) + + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + + 1/6*(1,3,2) - 1/6*(1,3)] + :: From 45190ac0b91b9025b446ab02f60e66a8c94a6304 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 20 Mar 2015 13:03:08 -0700 Subject: [PATCH 148/665] 18002: general sage convention --- .../finite_dimensional_algebras_with_basis.py | 1 - src/sage/categories/semisimple_algebras.py | 29 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 8d9558576d6..fd057a385e7 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -398,7 +398,6 @@ def orthogonal_idempotents(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index bc70c5b0f07..e8994610be6 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -108,23 +108,23 @@ class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def _orthogonal_decomposition(self, listGen=None, topLevel=True): + def _orthogonal_decomposition(self, generators=None, topLevel=True): r""" - Decompose a commutative finite dimensional semi-simple - algebra ``A`` into a direct sum of simple A-modules. + Return a list of orthogonal idempotents of a semisimple + commutative finite dimensional algebra ``self``. INPUT: - ``self`` a finite dimensional semisimple commutative algebra. + - ``generators`` a list of generators of ``self``. By + default it will be the basis of ``self``. OUTPUT: - - list of elements of ``self`` each generating a simple - submodule of ``self`` in direct sum with the others. - The list is maximal. - - Return a list of generators of simple A-modules. + - list of elements of ``self`` each generating a one + dimensional simple submodule of ``self`` in direct + sum with the others. The list is maximal. EXAMPLES:: @@ -146,8 +146,8 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): operations. """ # Terminal case and stuffs - if listGen is None: - listGen = self.basis().list() + if generators is None: + generators = self.basis().list() if self.dimension() == 1: if topLevel: return self.basis().list() @@ -158,15 +158,14 @@ def _orthogonal_decomposition(self, listGen=None, topLevel=True): res = [] B = self.basis() while len(res) < 2: - if listGen == []: + if generators == []: raise Exception("Unable to fully decompose...") - curGen = listGen.pop() + gen = generators.pop() phi = self.module_morphism(on_basis=lambda i: - curGen*B[i], + gen*B[i], codomain=self, triangular=True) - aMat = phi.matrix(self.base_ring()) - res = aMat.eigenspaces_right() + res = phi.matrix(self.base_ring()).eigenspaces_right() # Gotcha! Let's settle the algebra... From 7f8a5de6931f2af8e5bafadd7ebcc2d5d9f25ded Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Sat, 21 Mar 2015 00:07:07 +0100 Subject: [PATCH 149/665] Trac 17543: remove unnecessary check --- src/sage/modular/abvar/finite_subgroup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index dc187e9d042..e92ff366fe9 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -642,8 +642,6 @@ def _element_constructor_(self, x, check=True): ... TypeError: x does not define an element of self """ - if isinstance(x, self.element_class) and x.parent() is self: - return x if isinstance(x, TorsionPoint): if x.parent() == self: return self.element_class(self, x.element(), check=False) From 6bb064b3d8f3a109196cc5814522ac179be45f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 20 Mar 2015 16:51:38 -0700 Subject: [PATCH 150/665] 11111: proofreading with Franco; added trivial radical_basis in the semisimple case; removed SemisimpleAlgebra from the global name space --- src/sage/categories/algebras.py | 6 +- src/sage/categories/all.py | 1 - .../finite_dimensional_algebras_with_basis.py | 43 ++++-- .../finite_dimensional_algebras_with_basis.py | 145 ++++++++++-------- src/sage/categories/semisimple_algebras.py | 24 +++ 5 files changed, 141 insertions(+), 78 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index fe855a5330d..1ec4cb4a86a 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -153,12 +153,14 @@ def algebra_generators(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: S = A.semisimple_quotient() sage: S.algebra_generators() Finite family {'y': B['y'], 'x': B['x'], 'b': 0, 'a': 0} - .. TODO:: this could possibly remove the elements that retract to zero + .. TODO:: this could possibly remove the elements that retract to zero. """ return self.ambient().algebra_generators().map(self.retract) diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index c7397eb38fb..233ea32ce9e 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -74,7 +74,6 @@ from monoid_algebras import MonoidAlgebras from group_algebras import GroupAlgebras from matrix_algebras import MatrixAlgebras -from semisimple_algebras import SemisimpleAlgebras # ideals from ring_ideals import RingIdeals diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py index 0303e44e0dd..1a2181b38e0 100644 --- a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -1,8 +1,8 @@ r""" -Examples of finite dimensional algebras with basis +Example of a finite dimensional algebra with basis """ #***************************************************************************** -# Copyright (C) 2008-2014 Franco Saliola +# Copyright (C) 2008-2015 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -14,11 +14,13 @@ class KroneckerQuiverPathAlgebra(CombinatorialFreeModule): r""" - An example of a finite dimensional algebra with basis: the path algebra of - the Kronecker quiver. + An example of a finite dimensional algebra with basis: the path + algebra of the Kronecker quiver. - This class illustrates a minimal implementation of a finite dimensional - algebra with basis. + This class illustrates a minimal implementation of a finite + dimensional algebra with basis. See + :class:`sage.quiver.algebra.PathAlgebra` for a full-featured + implementation of path algebras. """ def __init__(self, base_ring): @@ -26,7 +28,9 @@ def __init__(self, base_ring): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: TestSuite(A).run() """ basis_keys = ['x', 'y', 'a', 'b'] @@ -35,16 +39,22 @@ def __init__(self, base_ring): 'yy':'y', 'ay':'a', 'by':'b' } - CombinatorialFreeModule.__init__(self, base_ring, basis_keys, category = FiniteDimensionalAlgebrasWithBasis(base_ring)) + CombinatorialFreeModule.__init__( + self, base_ring, basis_keys, + category=FiniteDimensionalAlgebrasWithBasis(base_ring)) def _repr_(self): r""" EXAMPLES:: sage: FiniteDimensionalAlgebrasWithBasis(QQ).example() # indirect doctest - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field """ - return "An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over %s "%(self.base_ring()) + return "An example of a finite dimensional algebra with basis: " \ + "the path algebra of the Kronecker quiver " \ + "(containing the arrows a:x->y and b:x->y) over %s "%(self.base_ring()) def one(self): r""" @@ -100,14 +110,16 @@ def product_on_basis(self, w1, w2): @cached_method def algebra_generators(self): r""" - Return the generators of this algebra. + Return algebra generators for this algebra. .. SEEALSO:: :meth:`Algebras.ParentMethods.algebra_generators`. EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.algebra_generators() Finite family {'y': y, 'x': x, 'b': b, 'a': a} """ @@ -115,9 +127,11 @@ def algebra_generators(self): def _repr_term(self, p): r""" - This method customizes the string representation of the basis element indexed by ``p``. + This method customizes the string representation of the basis + element indexed by ``p``. - In this example, we just return the string representation of ``p`` itself. + In this example, we just return the string representation of + ``p`` itself. EXAMPLES:: @@ -128,4 +142,3 @@ def _repr_term(self, p): return str(p) Example = KroneckerQuiverPathAlgebra - diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 46bdb05703b..0c72ea0991a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -3,8 +3,8 @@ """ #***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) -# 2011-2014 Nicolas M. Thiery -# 2011-2014 Franco Saliola +# 2011-2015 Nicolas M. Thiery +# 2011-2015 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -51,17 +51,20 @@ def radical_basis(self, cache_products=True): .. NOTE:: - This implementation also works for algebras over fields of - finite characteristic `p` in which we can compute `x^{1/p}`. + This implementation handles algebras over fields of + characteristic zero (using Dixon's lemma) or fields of + characteristic `p` in which we can compute `x^{1/p}`. INPUT: - - ``cache_products`` -- boolean (default: ``True``); if ``True`` - then all products computed in this method are cached. + - ``cache_products`` -- a boolean (default: ``True``); if + ``True`` then all products computed in this method are cached. OUTPUT: - - ``list`` of elements of ``self`` + - a list of elements of ``self``. + + .. SEEALSO:: :meth:`radical`, :class:`SemisimpleAlgebras` EXAMPLES:: @@ -72,7 +75,8 @@ def radical_basis(self, cache_products=True): sage: A.radical_basis() [a, b] - We construct the group algebra of the Klein Four-Group over the rationals:: + We construct the group algebra of the Klein Four-Group + over the rationals:: sage: A = KleinFourGroup().algebra(QQ) @@ -86,15 +90,44 @@ def radical_basis(self, cache_products=True): tells us that the group algebra is semisimple. So its radical is the zero ideal:: + sage: A in Algebras(QQ).SemiSimple() + True sage: A.radical_basis() [] Let's work instead over a field of characteristic `2`:: sage: A = KleinFourGroup().algebra(GF(2)) + sage: A in Algebras(GF(2)).SemiSimple() + False sage: A.radical_basis() [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] + We now implement the algebra `A = K[x] / x^p-1`, where `K` + is a finite field of characteristic `p`, and check its + radical; alas, we currently need to wrap `A` to make it a + proper :class:`ModulesWithBasis`:: + + sage: class AnAlgebra(CombinatorialFreeModule): + ....: def __init__(self, F): + ....: R. = PolynomialRing(F) + ....: I = R.ideal(x**F.characteristic()-F.one()) + ....: self._xbar = R.quotient(I).gen() + ....: basis_keys = [self._xbar**i for i in range(F.characteristic())] + ....: CombinatorialFreeModule.__init__(self, F, basis_keys, + ....: category=FiniteDimensionalAlgebrasWithBasis(F)) + ....: def one(self): + ....: return self.basis()[self.base_ring().one()] + ....: def product_on_basis(self, w1, w2): + ....: return self.from_vector(vector(w1*w2)) + sage: AnAlgebra(GF(3)).radical_basis() + [B[1] + 2*B[xbar^2], B[xbar] + 2*B[xbar^2]] + sage: AnAlgebra(GF(16,'a')).radical_basis() + [B[1] + B[xbar]] + sage: AnAlgebra(GF(49,'a')).radical_basis() + [B[1] + 6*B[xbar^6], B[xbar] + 6*B[xbar^6], B[xbar^2] + 6*B[xbar^6], + B[xbar^3] + 6*B[xbar^6], B[xbar^4] + 6*B[xbar^6], B[xbar^5] + 6*B[xbar^6]] + TESTS:: sage: A = KleinFourGroup().algebra(GF(2)) @@ -103,54 +136,23 @@ def radical_basis(self, cache_products=True): sage: A.radical_basis(cache_products=False) [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] - :: - - sage: A = KleinFourGroup().algebra(QQ) + sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) + sage: A.radical_basis.__module__ sage: A.radical_basis(cache_products=True) [] sage: A.radical_basis(cache_products=False) [] - - .. TODO:: explain and check this example - - :: - - sage: class AnAlgebra(CombinatorialFreeModule): - ... def __init__(self, F): - ... R. = PolynomialRing(F) - ... I = R.ideal(x**F.characteristic()-F.one()) - ... self._xbar = R.quotient(I).gen() - ... basis_keys = [self._xbar**i for i in range(F.characteristic())] - ... CombinatorialFreeModule.__init__(self, F, basis_keys, - ... category = FiniteDimensionalAlgebrasWithBasis(F)) - ... def one(self): - ... return self.basis()[self.base_ring().one()] - ... def product_on_basis(self, w1, w2): - ... return self.from_vector(vector(w1*w2)) - sage: AnAlgebra(GF(3)).radical_basis() - [B[1] + 2*B[xbar^2], B[xbar] + 2*B[xbar^2]] - sage: AnAlgebra(GF(16,'a')).radical_basis() - [B[1] + B[xbar]] - sage: AnAlgebra(GF(49,'a')).radical_basis() - [B[1] + 6*B[xbar^6], B[xbar] + 6*B[xbar^6], B[xbar^2] + 6*B[xbar^6], B[xbar^3] + 6*B[xbar^6], B[xbar^4] + 6*B[xbar^6], B[xbar^5] + 6*B[xbar^6]] - - .. SEEALSO:: :meth:`radical`, :class:`SemisimpleAlgebras` - - AUTHORS: TODO: polish this! - - - Franco Saliola """ F = self.base_ring() if not F.is_field(): - raise NotImplementedError, "the base ring must be a field" + raise NotImplementedError("the base ring must be a field") p = F.characteristic() from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + product_on_basis = self.product_on_basis if cache_products is True: - product_on_basis = cached_function(self.product_on_basis) - else: - product_on_basis = self.product_on_basis + product_on_basis = cached_function(product_on_basis) if p == 0: keys = self.basis().keys() @@ -192,6 +194,11 @@ def radical(self): r""" Return the Jacobson radical of ``self``. + This uses :meth:`radical_basis`, whose default + implementation handles algebras over fields of + characteristic zero or fields of characteristic `p` in + which we can compute `x^{1/p}`. + .. SEEALSO:: :meth:`radical_basis`, :meth:`semisimple_quotient` EXAMPLES:: @@ -204,9 +211,16 @@ def radical(self): Radical of An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + + The radical is an ideal of `A`, and thus a finite + dimensional non unital associative algebra:: + sage: from sage.categories.associative_algebras import AssociativeAlgebras sage: radical in AssociativeAlgebras(QQ).WithBasis().FiniteDimensional() True + sage: radical in Algebras(QQ) + False + sage: radical.dimension() 2 sage: radical.basis() @@ -218,10 +232,10 @@ def radical(self): .. TODO:: - - This is in fact an ideal. - - Add references - - Pickling by construction, as ``A.center()`` - - Lazy evaluation of ``_repr_`` + - Tell Sage that the radical is in fact an ideal; + - Add references; + - Pickling by construction, as ``A.center()``; + - Lazy evaluation of ``_repr_``. TESTS:: @@ -229,8 +243,8 @@ def radical(self): """ category = AssociativeAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Subobjects() radical = self.submodule(self.radical_basis(), - category = category, - already_echelonized = True) + category=category, + already_echelonized=True) radical.rename("Radical of {}".format(self)) return radical @@ -246,13 +260,15 @@ def semisimple_quotient(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: a,b,x,y = sorted(A.basis()) sage: S = A.semisimple_quotient(); S Semisimple quotient of An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: S in SemisimpleAlgebras + sage: S in Algebras(QQ).Semisimple() True sage: S.basis() Finite family {'y': B['y'], 'x': B['x']} @@ -260,10 +276,18 @@ def semisimple_quotient(self): sage: (xs + ys) * xs B['x'] + Sanity check: the semisimple quotient of the `n`-th + descent algebra of the symmetric group is of dimension the + number of partitions of `n`:: + + sage: [ DescentAlgebra(QQ,n).B().semisimple_quotient().dimension() + ....: for n in range(6) ] + [1, 1, 2, 3, 5, 7] + sage: [Partitions(n).cardinality() for n in range(10)] + [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] + .. TODO:: - - This example is not very interesting because the - semisimple quotient is actually a subalgebra. - Pickling by construction, as ``A.center()`` - Lazy evaluation of ``_repr_`` @@ -272,8 +296,7 @@ def semisimple_quotient(self): sage: TestSuite(S).run() """ ring = self.base_ring() - category=Algebras(ring).WithBasis().FiniteDimensional().Quotients() \ - & SemisimpleAlgebras(ring) + category = Algebras(ring).WithBasis().FiniteDimensional().Quotients().Semisimple() result = self.quotient(self.radical(), category=category) result.rename("Semisimple quotient of {}".format(self)) return result @@ -286,14 +309,16 @@ def center_basis(self): OUTPUT: - - ``list`` of elements of ``self`` + - a list of elements of ``self``. .. SEEALSO:: :meth:`center` EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.center_basis() [x + y] """ @@ -326,7 +351,7 @@ def center(self): True sage: [c.lift() for c in center.basis()] [x + y] - sage: DihedralGroup(6).algebra(QQ).center() in SemisimpleAlgebras + sage: DihedralGroup(6).algebra(QQ).center() in Algebras(QQ).Semisimple() True .. TODO:: @@ -340,7 +365,7 @@ def center(self): """ category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() if self in SemisimpleAlgebras: - category = category & SemisimpleAlgebras(self.base_ring()) + category = category.Semisimple() center = self.submodule(self.center_basis(), category = category, already_echelonized = True) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 363f1587f30..bcc11d7bbe9 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -62,3 +62,27 @@ def super_categories(self): """ R = self.base_ring() return [Algebras(R)] + + # TODO: trivial implementations for semisimple_quotient + + class ParentMethods: + + def radical_basis(self, **keywords): + r""" + Return a basis of the Jacobson radical of this algebra. + + - ``keywords`` -- for compatibility; ignored. + + OUTPUT: the empty list since this algebra is semisimple + + EXAMPLES:: + + sage: A = SymmetricGroup(4).algebra(QQ) + sage: A.radical_basis() + [] + + TESTS:: + + sage: A.radical_basis.__module__ + """ + return [] From 8c6759b811a557f51bdf7a568190bef3cf9eaaea Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Fri, 20 Mar 2015 17:35:02 -0700 Subject: [PATCH 151/665] 16659: clean _orthogonal_idempotent --- src/sage/categories/semisimple_algebras.py | 96 ++++++++++++---------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index e8994610be6..7ce1002e74e 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -101,14 +101,14 @@ def orthogonal_idempotents(self): [B['y'], B['x']] """ return [x.lift() - for x in self.center().central_orthogonal_idempotents()] + for x in self.center().orthogonal_idempotents()] class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def _orthogonal_decomposition(self, generators=None, topLevel=True): + def _orthogonal_decomposition(self, generators=None): r""" Return a list of orthogonal idempotents of a semisimple commutative finite dimensional algebra ``self``. @@ -126,6 +126,20 @@ def _orthogonal_decomposition(self, generators=None, topLevel=True): dimensional simple submodule of ``self`` in direct sum with the others. The list is maximal. + ALGORITHM: + + A commutative semisimple algebra `A` is a direct + sum of dimension 1 sub-algebras thanks to Schur + Lemma. The algorithm is recursive a proceed in two + steps: + + 0. If `A` is of dimension 1, return a non zero + element. + 1. Find a generator `a \in A` such that the + morphism `x \mapsto ax` has at least two (right) + eigenspaces. + 2. Decompose both eigenspaces recursively. + EXAMPLES:: sage: G5 = SymmetricGroup(5) @@ -142,52 +156,48 @@ def _orthogonal_decomposition(self, generators=None, topLevel=True): .. TODO:: - Improve the function by only using matrix - operations. + Improve speed by only using matrix operations, if + possible. """ - # Terminal case and stuffs + # Main program if generators is None: generators = self.basis().list() if self.dimension() == 1: - if topLevel: - return self.basis().list() - else: - return [x.lift() for x in self.basis()] - - # Searching for a good generator... - res = [] - B = self.basis() - while len(res) < 2: - if generators == []: - raise Exception("Unable to fully decompose...") - gen = generators.pop() - phi = self.module_morphism(on_basis=lambda i: - gen*B[i], - codomain=self, - triangular=True) - res = phi.matrix(self.base_ring()).eigenspaces_right() - - # Gotcha! Let's settle the algebra... - - res = [vector_space for _, vector_space in res] - res = [[self.from_vector(vector) - for vector in eigenspace.basis()] - for eigenspace in res] - - decomp = [self.submodule(v, - category=SemisimpleAlgebras(self.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) - for v in res] - - # Recursive on decomp - res = [x for space in decomp for x in - space._orthogonal_decomposition(topLevel=False)] - if topLevel: - return res - else: - return map(lambda x: x.lift(), res) + return self.basis().list() + + def rec(space, generators): + if space.dimension() == 1: + return space.basis().list() + eigenspaces = [] + + # Searching a good generator... + while len(eigenspaces) < 2: + if generators == []: + raise Exception("Unable to fully decompose...") + gen = generators.pop() + phi = space.module_morphism(on_basis=lambda i: + gen*space.basis()[i], + codomain=space, + triangular=True) + eigenspaces = phi.matrix(space.base_ring()).eigenspaces_right() + + # Gotcha! Let's settle the algebra... + eigenspaces = [vector_space for _, vector_space in eigenspaces] + eigenspaces = [[space.from_vector(vector) + for vector in eigenspace.basis()] + for eigenspace in eigenspaces] + decomp = [space.submodule(v, + category=SemisimpleAlgebras(space.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) + for v in eigenspaces] + + # Decompose recursively each eigenspace + return map(lambda x: x.lift(), [x for eigenspace in + decomp for x in rec(eigenspace, eigenspace.basis().list())]) + + return rec(self, generators) @cached_method - def central_orthogonal_idempotents(self, dimSimple=False): + def orthogonal_idempotents(self): r""" Return the minimum set of central orthogonal idempotents of ``self``. @@ -203,7 +213,7 @@ def central_orthogonal_idempotents(self, dimSimple=False): sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() - sage: orth = Z5.central_orthogonal_idempotents() + sage: orth = Z5.orthogonal_idempotents() sage: orth [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + From c175955f2bef7275458e243f17bf5dcc1833ddc0 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 01:39:46 +0100 Subject: [PATCH 152/665] minor changes --- src/sage/combinat/tableau.py | 43 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index c6ca285b6bc..f8536e2cafa 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -276,8 +276,8 @@ def __classcall_private__(cls, t): if isinstance(t, cls): return t - # CombinatorialObject verifies that t is a list - # We must verify t is a list of iterables + # We must verify ``t`` is a list of iterables, and also + # normalize it to be a list of tuples. try: t = map(tuple, t) except TypeError: @@ -326,31 +326,33 @@ def __init__(self, parent, t): t = map(tuple, t) ClonableList.__init__(self, parent, t) + # This dispatches the input verification to the :meth:`check` + # method. def __eq__(self, other): r""" Check whether ``self`` is equal to ``other``. - + TODO: - + This overwrites the equality check of - :class:`sage.structure.list_clone.ClonableList` + :class:`~sage.structure.list_clone.ClonableList` in order to circumvent the coercion framework. Eventually this should be solved more elegantly, for example along the lines of what was done for k-tableaux. - + For now, two elements are equal if their underlying defining lists compare equal. - + INPUT: - + ``other`` -- the element that ``self`` is compared to - + OUTPUT: - + A Boolean. - + TESTS:: sage: t = Tableau([[1,2]]) @@ -367,19 +369,19 @@ def __eq__(self, other): def __ne__(self, other): r""" Check whether ``self`` is unequal to ``other``. - + See the documentation of :meth:`__eq__`. - + INPUT: - + ``other`` -- the element that ``self`` is compared to - + OUTPUT: - + A Boolean. - + TESTS:: - + sage: t = Tableau([[2,3],[1]]) sage: t != [] True @@ -391,7 +393,7 @@ def __ne__(self, other): def check(self): r""" - Check that ``self`` is a valid straight shape tableau. + Check that ``self`` is a valid straight-shape tableau. EXAMPLES:: @@ -403,7 +405,8 @@ def check(self): ... ValueError: A tableau must be a list of iterables of weakly decreasing length. """ - # and that it has partition shape + # Check that it has partition shape. That's all we require from a + # general tableau. from sage.combinat.partition import _Partitions if not map(len, self) in _Partitions: raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") From a715d2ff4cfe4d2205925e9a5ca4aa1254cb6cee Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 02:25:06 +0100 Subject: [PATCH 153/665] analogous changes for skew tableaux --- src/sage/combinat/skew_tableau.py | 105 ++++++++++++++++++++++++++---- src/sage/combinat/tableau.py | 2 - 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index fed94c1d4d5..0d401deb4e4 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -29,7 +29,6 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element import Element from sage.categories.sets_cat import Sets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -40,14 +39,14 @@ from sage.matrix.all import zero_matrix import itertools -from sage.combinat.combinat import CombinatorialObject +from sage.structure.list_clone import ClonableList from sage.combinat.partition import Partition -from sage.combinat.tableau import TableauOptions +from sage.combinat.tableau import Tableau, TableauOptions from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.words import Words -class SkewTableau(CombinatorialObject, Element): +class SkewTableau(ClonableList): """ A skew tableau. @@ -116,7 +115,92 @@ def __init__(self, parent, st): ... TypeError: 'tuple' object does not support item assignment """ - for row in st: + ClonableList.__init__(self, parent, st) + + def __eq__(self, other): + r""" + Check whether ``self`` is equal to ``other``. + + TODO: + + This overwrites the equality check of + :class:`~sage.structure.list_clone.ClonableList` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + k-tableaux. + + For now, two elements are equal if their underlying + defining lists compare equal. + + INPUT: + + ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A Boolean. + + TESTS:: + + sage: t = SkewTableau([[None,1,2]]) + sage: t == 0 + False + sage: t == SkewTableaux()([[None,1,2]]) + True + + sage: s = SkewTableau([[1,2]]) + sage: s == 0 + False + sage: s == Tableau([[1,2]]) + True + """ + if isinstance(other, (Tableau, SkewTableau)): + return list(self) == list(other) + else: + return list(self) == other + + def __ne__(self, other): + r""" + Check whether ``self`` is unequal to ``other``. + + See the documentation of :meth:`__eq__`. + + INPUT: + + ``other`` -- the element that ``self`` is compared to + + OUTPUT: + + A Boolean. + + TESTS:: + + sage: t = Tableau([[2,3],[1]]) + sage: t != [] + True + """ + if isinstance(other, (Tableau, SkewTableau)): + return list(self) != list(other) + else: + return list(self) != other + + def check(self): + r""" + Check that ``self`` is a valid skew tableau. This is currently far too + liberal, and only checks some trivial things. + + EXAMPLES:: + + sage: t = SkewTableau([[None,1,1],[2]]) + sage: t.check() + + sage: t = SkewTableau([[None, None, 1], [2, 4], [], [3, 4, 5]]) + Traceback (most recent call last): + ... + TypeError: a skew tableau cannot have an empty list for a row + """ + for row in self: try: iter(row) except TypeError: @@ -124,9 +208,6 @@ def __init__(self, parent, st): if not row: raise TypeError("a skew tableau cannot have an empty list for a row") - CombinatorialObject.__init__(self, st) - Element.__init__(self, parent) - def __setstate__(self, state): r""" In order to maintain backwards compatibility and be able to unpickle @@ -135,8 +216,6 @@ def __setstate__(self, state): EXAMPLES:: - sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+H,*\xc9,\xc9\xcc\xcf\xe3\n\x80\xb1\xe2\x93s\x12\x8b\x8b\xb9\n\x195\x1b\x0b\x99j\x0b\x995BY\xe33\x12\x8b3\nY\xfc\x80\xac\x9c\xcc\xe2\x92B\xd6\xd8B6\r\x88IE\x99y\xe9\xc5z\x99y%\xa9\xe9\xa9E\\\xb9\x89\xd9\xa9\xf10N!{(\xa3qkP!G\x06\x90a\x04dp\x82\x18\x86@\x06Wji\x92\x1e\x00x0.\xb5') - [3, 2, 1] sage: loads(dumps( SkewTableau([[1,1], [3,2,1]]) )) # indirect doctest [[1, 1], [3, 2, 1]] """ @@ -205,10 +284,10 @@ def _repr_compact(self): sage: Tableau([])._repr_compact() '-' """ - if not self._list: + if not self: return '-' str_rep = lambda x: '%s'%x if x is not None else '.' - return '/'.join(','.join(str_rep(r) for r in row) for row in self._list) + return '/'.join(','.join(str_rep(r) for r in row) for row in self) def pp(self): """ @@ -2162,7 +2241,7 @@ def __iter__(self): """ from ribbon_tableau import RibbonTableaux_shape_weight_length for x in RibbonTableaux_shape_weight_length(self.p, self.mu, 1): - yield self.element_class(self, x._list) + yield self.element_class(self, x[:]) # October 2012: fixing outdated pickles which use the classes being deprecated from sage.structure.sage_object import register_unpickle_override diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index f8536e2cafa..e8abdfa1780 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -74,7 +74,6 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.structure.element import Element from sage.structure.global_options import GlobalOptions from sage.structure.unique_representation import UniqueRepresentation from sage.structure.list_clone import ClonableList @@ -83,7 +82,6 @@ from sage.rings.infinity import PlusInfinity from sage.rings.arith import factorial from sage.rings.integer import Integer -from sage.combinat.combinat import CombinatorialObject from sage.combinat.composition import Composition, Compositions from integer_vector import IntegerVectors import sage.libs.symmetrica.all as symmetrica From 0ec56c8542f0795f46da0909f51d6df0d4dc973a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 02:52:36 +0100 Subject: [PATCH 154/665] old pickles are old --- src/sage/combinat/ribbon_shaped_tableau.py | 2 -- src/sage/combinat/ribbon_tableau.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 96208c3969b..28216fc47a1 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -105,8 +105,6 @@ def __setstate__(self, state): EXAMPLES:: - sage: loads( 'x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@\x14]\x8a\x0e\xdf\xb8\x968"\xceZ|\x00x\xef5\x11') - [[None, 1], [2, 3]] - sage: loads(dumps( RibbonTableau([[None, 1],[2,3]]) )) [[None, 1], [2, 3]] """ From 5b1b2fb81c73b79a695de42d8e1ea5935d2cee26 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 08:14:28 +0100 Subject: [PATCH 155/665] optimize add_entry on tableau --- src/sage/combinat/tableau.py | 53 ++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index e8abdfa1780..141f14b92da 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1722,7 +1722,7 @@ def restrict(self, n): Category of elements of Semistandard tableaux """ res = [ [y for y in row if y <= n] for row in self ] - res = [row for row in res if row != []] + res = [row for row in res if row] # attempt to return a tableau of the same type try: return self.parent()( res ) @@ -2634,10 +2634,30 @@ def cocharge(self): return self.to_word().cocharge() - def add_entry(self,cell,m): + def add_entry(self, cell, m): """ - Set the entry in ``cell`` equal to ``m``. If the cell does not exist then - extend the tableau, otherwise just replace the entry. + Return the result of setting the entry in cell ``cell`` equal + to ``m`` in the tableau ``self``. + + This tableau has larger size than ``self`` if ``cell`` does not + belong to the shape of ``self``; otherwise, the tableau has the + same shape as ``self`` and has the appropriate entry replaced. + + INPUT: + + - ``cell`` -- a pair of nonnegative integers + + OUTPUT: + + The tableau ``self`` with the entry in cell ``cell`` set to ``m``. This + entry overwrites an existing entry if ``cell`` already belongs to + ``self``, or is added to the tableau if ``cell`` is a cocorner of the + shape ``self``. (Either way, the input is not modified.) + + .. NOTE:: + + Both coordinates of ``cell`` are interpreted as starting at `0`. + So, ``cell == (0, 0)`` corresponds to the northwesternmost cell. EXAMPLES:: @@ -2664,21 +2684,24 @@ def add_entry(self,cell,m): IndexError: (2, 2) is not an addable cell of the tableau """ - tab=self.to_list() - (r,c)=cell + tab = self.to_list() + (r, c) = cell try: - tab[r][c]=m # will work if we are replacing an entry + tab[r][c] = m # will work if we are replacing an entry except IndexError: # Only add a new row if (r,c) is an addable cell (previous code - # added added m to the end of row r independently of the value of c) - if (r,c) in self.shape().outside_corners(): # an addable node - if r==len(tab): - tab.append([]) - - tab[r].append(m) - + # added m to the end of row r independently of the value of c) + if r >= len(tab): + if r == len(tab) and c == 0: + tab.append([m]) + else: + raise IndexError('%s is not an addable cell of the tableau' % ((r,c),)) else: - raise IndexError('%s is not an addable cell of the tableau' % ((r,c),)) + tab_r = tab[r] + if c == len(tab_r): + tab_r.append(m) + else: + raise IndexError('%s is not an addable cell of the tableau' % ((r,c),)) # attempt to return a tableau of the same type as self if tab in self.parent(): From 63301537d445b5a856c77b375193fdb8fa39b9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sat, 21 Mar 2015 00:19:39 -0700 Subject: [PATCH 156/665] 11111: typo fixes, ... --- .../finite_dimensional_algebras_with_basis.py | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 0c72ea0991a..41e4592a960 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -90,7 +90,7 @@ def radical_basis(self, cache_products=True): tells us that the group algebra is semisimple. So its radical is the zero ideal:: - sage: A in Algebras(QQ).SemiSimple() + sage: A in Algebras(QQ).Semisimple() True sage: A.radical_basis() [] @@ -98,7 +98,7 @@ def radical_basis(self, cache_products=True): Let's work instead over a field of characteristic `2`:: sage: A = KleinFourGroup().algebra(GF(2)) - sage: A in Algebras(GF(2)).SemiSimple() + sage: A in Algebras(GF(2)).Semisimple() False sage: A.radical_basis() [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] @@ -138,6 +138,7 @@ def radical_basis(self, cache_products=True): sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) sage: A.radical_basis.__module__ + 'sage.categories.finite_dimensional_algebras_with_basis' sage: A.radical_basis(cache_products=True) [] sage: A.radical_basis(cache_products=False) @@ -288,7 +289,7 @@ def semisimple_quotient(self): .. TODO:: - - Pickling by construction, as ``A.center()`` + - Pickling by construction, as ``A.semisimple_quotient()``? - Lazy evaluation of ``_repr_`` TESTS:: @@ -351,12 +352,15 @@ def center(self): True sage: [c.lift() for c in center.basis()] [x + y] + + The center of a semisimple algebra is semisimple:: + sage: DihedralGroup(6).algebra(QQ).center() in Algebras(QQ).Semisimple() True .. TODO:: - - Pickling by construction, as ``A.center()`` + - Pickling by construction, as ``A.center()``? - Lazy evaluation of ``_repr_`` TESTS:: @@ -367,8 +371,8 @@ def center(self): if self in SemisimpleAlgebras: category = category.Semisimple() center = self.submodule(self.center_basis(), - category = category, - already_echelonized = True) + category=category, + already_echelonized=True) center.rename("Center of {}".format(self)) return center @@ -377,10 +381,10 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ Return the matrix of the action of ``self`` on the algebra. - INPUT:: + INPUT: - ``base_ring`` -- the base ring for the matrix to be constructed - - ``action`` -- a function (default: :func:`operator.mul`) + - ``action`` -- a bivariate function (default: :func:`operator.mul`) - ``side`` -- 'left' or 'right' (default: 'right') EXAMPLES:: @@ -394,6 +398,13 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): [0 0 0 0 0 1] [0 1 0 0 0 0] [0 0 0 1 0 0] + sage: a.to_matrix(side='right') + [0 0 1 0 0 0] + [0 0 0 1 0 0] + [1 0 0 0 0 0] + [0 1 0 0 0 0] + [0 0 0 0 0 1] + [0 0 0 0 1 0] sage: a.to_matrix(base_ring=RDF, side="left") [0.0 0.0 1.0 0.0 0.0 0.0] [0.0 0.0 0.0 0.0 1.0 0.0] @@ -402,7 +413,7 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): [0.0 1.0 0.0 0.0 0.0 0.0] [0.0 0.0 0.0 1.0 0.0 0.0] - AUTHORS: Mike Hansen # TODO: polish this! + AUTHORS: Mike Hansen, ... """ basis = self.parent().basis() action_left = action From 27558f079054f5db0ff8edf90594dcf3484d3c98 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 08:35:28 +0100 Subject: [PATCH 157/665] a few more optimizations --- src/sage/combinat/tableau.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 141f14b92da..ccdf76804df 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -50,8 +50,6 @@ - Move methods that only apply to semistandard tableaux from tableau to semistandard tableau - - Tableau([[]]) is standard and distinct from Tableau([]). Is this bad? - - Copy/move functionality to skew tableaux - Add a class for tableaux of a given shape (eg Tableaux_shape) @@ -301,7 +299,7 @@ def __init__(self, parent, t): Tableaux sage: s is t # identical tableaux are distinct objects False - + A tableau is immutable, see :trac:`15862`:: sage: T = Tableau([[1,2],[2]]) @@ -405,9 +403,12 @@ def check(self): """ # Check that it has partition shape. That's all we require from a # general tableau. - from sage.combinat.partition import _Partitions - if not map(len, self) in _Partitions: - raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") + lens = map(len, self) + for (a, b) in itertools.izip(lens, lens[1:]): + if a < b: + raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") + if lens and lens[-1] == 0: + raise ValueError("A tableau must not have empty rows.") def __setstate__(self, state): """ @@ -1449,7 +1450,7 @@ def is_column_strict(self): False sage: Tableau([[5, 3], [2, 4]]).is_column_strict() False - sage: Tableau([[]]).is_column_strict() + sage: Tableau([]).is_column_strict() True sage: Tableau([[1, 4, 2]]).is_column_strict() True From 72c8418602852f07adb19abb0475c2947ed0637a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 08:47:21 +0100 Subject: [PATCH 158/665] optimizing anti_restrict a bit --- src/sage/combinat/tableau.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index ccdf76804df..dacd4bd7dc3 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1846,14 +1846,9 @@ def anti_restrict(self, n): sage: t.anti_restrict(5) [[None, None, None], [None, None]] """ - t = [list(row) for row in self] # create deep copy of t - - for row in t: - for col in xrange(len(row)): - if row[col] <= n: - row[col] = None + t_new = [[None if g <= n else g for g in row] for row in self] from sage.combinat.skew_tableau import SkewTableau - return SkewTableau(t) + return SkewTableau(t_new) def to_list(self): """ From 2c94664e34fe9540b2a5c7c939dd1329d6037bf0 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 09:40:15 +0100 Subject: [PATCH 159/665] minor corrections to ribbon and ribbon-shape tableaux --- src/sage/combinat/ribbon_shaped_tableau.py | 108 +++++++++------------ src/sage/combinat/ribbon_tableau.py | 34 +++---- src/sage/combinat/skew_tableau.py | 2 +- src/sage/combinat/tableau.py | 3 +- 4 files changed, 63 insertions(+), 84 deletions(-) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 28216fc47a1..3c4019b3eb5 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -16,24 +16,28 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation from sage.combinat.skew_tableau import SkewTableau, StandardSkewTableaux from sage.combinat.tableau import TableauOptions from sage.combinat.permutation import Permutation, descents_composition_first, descents_composition_list, descents_composition_last -from sage.combinat.skew_partition import SkewPartition from sage.rings.integer import Integer -from combinat import CombinatorialObject -from sage.combinat.words.words import Words from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets class RibbonShapedTableau(SkewTableau): r""" - A ribbon. + A ribbon shaped tableau. - A ribbon is a skew tableau that does not contain a `2 \times 2` box. A - ribbon is given by a list of the rows from top to bottom. + For the purposes of this class, a ribbon shaped tableau is a skew + tableau whose shape is a skew partition which: + + - has at least one cell in row `1`; + + - has at least one cell in column `1`; + + - has exactly one cell in each of `q` consecutive diagonals, for + some nonnegative integer `q`. + + A ribbon is given by a list of the rows from top to bottom. EXAMPLES:: @@ -47,29 +51,40 @@ class RibbonShapedTableau(SkewTableau): [5, 4, 2] / [3, 1] The entries labeled by ``None`` correspond to the inner partition. - Using ``None`` is optional, the entries will be shifted accordingly. :: + Using ``None`` is optional; the entries will be shifted accordingly. :: sage: x = RibbonShapedTableau([[2,3],[1,4,5],[3,2]]); x.pp() . . . 2 3 . 1 4 5 3 2 + + TESTS:: + + sage: r = RibbonShapedTableau([[1], [2,3], [4, 5, 6]]) + sage: r.to_permutation() + [4, 5, 6, 2, 3, 1] + + sage: RibbonShapedTableau([[1,2],[3,4]]).evaluation() + [1, 1, 1, 1] """ @staticmethod def __classcall_private__(cls, r): r""" - Return a ribbon tableau object. + Return a ribbon shaped tableau object. EXAMPLES:: sage: RibbonShapedTableau([[2,3],[1,4,5]]) [[None, None, 2, 3], [1, 4, 5]] """ - if isinstance(r, list): - if len(r) == 0: - return StandardRibbonShapedTableaux()(r) - if all(isinstance(i, list) for i in r): - if all(all(j is None or (isinstance(j, (int, Integer)) and j>0) for j in i) for i in r): - return StandardRibbonShapedTableaux()(r) + try: + r = map(tuple, r) + except TypeError: + raise TypeError("r must be a list of positive integers") + if not r: + return StandardRibbonShapedTableaux()(r) + if all(all(j is None or (isinstance(j, (int, Integer)) and j>0) for j in i) for i in r): + return StandardRibbonShapedTableaux()(r) raise TypeError("r must be a list of positive integers") def __init__(self, parent, t): @@ -105,6 +120,8 @@ def __setstate__(self, state): EXAMPLES:: + sage: loads( 'x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@ 0 else 0 - def to_skew_tableau(self): - """ - This is deprecated in :trac:`14101` since :class:`RibbonShapedTableau` - inherits from :class:`SkewTableau`. - - EXAMPLES:: - - sage: RibbonShapedTableau([[2,3],[1,4,5]]).to_skew_tableau() - doctest:...: DeprecationWarning: this method is deprecated since ribbon shaped tableaux are skew partitions - See http://trac.sagemath.org/14101 for details. - [[None, None, 2, 3], [1, 4, 5]] - """ - from sage.misc.superseded import deprecation - deprecation(14101,'this method is deprecated since ribbon shaped tableaux are skew partitions') - return self - - def to_permutation(self): - """ - Returns the permutation corresponding to the ribbon tableau. - - EXAMPLES:: - - sage: r = RibbonShapedTableau([[1], [2,3], [4, 5, 6]]) - sage: r.to_permutation() - [4, 5, 6, 2, 3, 1] - """ - return Permutation(self.to_word()) - - def evaluation(self): - """ - Return the evaluation of the word from ribbon. - - EXAMPLES:: - - sage: RibbonShapedTableau([[1,2],[3,4]]).evaluation() - [1, 1, 1, 1] - """ - ed = self.to_word().evaluation_dict() - entries = ed.keys() - m = max(entries) + 1 if entries else -1 - return [ed.get(k,0) for k in range(1,m)] - class StandardRibbonShapedTableaux(StandardSkewTableaux): """ @@ -240,6 +215,15 @@ def __init__(self, category=None): StandardSkewTableaux.__init__(self, category=category) + def _repr_(self): + """ + TESTS:: + + sage: repr(StandardRibbonShapedTableaux()) # indirect doctest + 'Standard ribbon shaped tableaux' + """ + return "Standard ribbon shaped tableaux" + def __iter__(self): """ Iterate through ``self``. @@ -320,12 +304,12 @@ def from_permutation(self, p): class StandardRibbonShapedTableaux_shape(StandardRibbonShapedTableaux): """ - Class of standard ribbon tableaux of ribbon shape ``shape``. + Class of standard ribbon shaped tableaux of ribbon shape ``shape``. EXAMPLES:: sage: StandardRibbonShapedTableaux([2,2]) - Standard ribbon tableaux of shape [2, 2] + Standard ribbon shaped tableaux of shape [2, 2] sage: StandardRibbonShapedTableaux([2,2]).first() [[None, 2, 4], [1, 3]] sage: StandardRibbonShapedTableaux([2,2]).last() @@ -370,9 +354,9 @@ def _repr_(self): TESTS:: sage: StandardRibbonShapedTableaux([2,2]) - Standard ribbon tableaux of shape [2, 2] + Standard ribbon shaped tableaux of shape [2, 2] """ - return "Standard ribbon tableaux of shape %s"%list(self.shape) + return "Standard ribbon shaped tableaux of shape %s"%list(self.shape) def first(self): """ diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 4922b1db7fa..050b902f41f 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -35,9 +35,10 @@ class RibbonTableau(SkewTableau): r""" A ribbon tableau. - A ribbon is a skew tableau such that the skew shape does not - contain any `2 \times 2` boxes. A ribbon tableau is a skew tableau - that is partitioned into ribbons. + A ribbon is a connected skew shape which does not contain any + `2 \times 2` boxes. A ribbon tableau is a skew tableau + whose shape is partitioned into ribbons, each of which is filled + with identical entries. EXAMPLES:: @@ -65,6 +66,11 @@ class RibbonTableau(SkewTableau): sage: RibbonTableau(expr=[[1,1],[[5],[3,4],[1,2]]]) [[None, 1, 2], [None, 3, 4], [5]] + + TESTS:: + + sage: RibbonTableau([[0, 0, 3, 0], [1, 1, 0], [2, 0, 4]]).evaluation() + [2, 1, 1, 1] """ #The following method is private and will only get called #when calling RibbonTableau() directly, and not via element_class @@ -99,6 +105,8 @@ def __setstate__(self, state): EXAMPLES:: + sage: loads('x\x9c5\xcc\xbd\x0e\xc2 \x14@\xe1\xb4Z\x7f\xd0\x07\xc1\x85D}\x8f\x0e\x8d\x1d\t\xb9\x90\x1bJ\xa44\x17\xe8h\xa2\x83\xef-\xda\xb8\x9do9\xcf\xda$\xb0(\xcc4j\x17 \x8b\xe8\xb4\x9e\x82\xca\xa0=\xc2\xcc\xba\x1fo\x8b\x94\xf1\x90\x12\xa3\xea\xf4\xa2\xfaA+\xde7j\x804\xd0\xba-\xe5]\xca\xd4H\xdapI[\xde.\xdf\xe8\x82M\xc2\x85\x8c\x16#\x1b\xe1\x8e\xea\x0f\xda\xf5\xd5\xf9\xdd\xd1\x1e%1>\x14]\x8a\x0e\xdf\xb8\x968"\xceZ|\x00x\xef5\x11') # not tested -- broken + [[None, 1], [2, 3]] sage: loads(dumps( RibbonTableau([[None, 1],[2,3]]) )) [[None, 1], [2, 3]] """ @@ -151,20 +159,6 @@ def to_word(self): w += row return Word(w) - def evaluation(self): - """ - Return the evaluation of the ribbon tableau. - - EXAMPLES:: - - sage: RibbonTableau([[0, 0, 3, 0], [1, 1, 0], [2, 0, 4]]).evaluation() - [2, 1, 1, 1] - """ - ed = self.to_word().evaluation_dict() - entries = ed.keys() - m = max(entries) + 1 if entries else -1 - return [ed.get(k,0) for k in range(1,m)] - ##################### # Ribbon Tableaux # ##################### @@ -179,7 +173,7 @@ class RibbonTableaux(Parent, UniqueRepresentation): .. NOTE:: - Here we inpose the condition that the ribbon tableaux are semistandard. + Here we impose the condition that the ribbon tableaux are semistandard. INPUT(Optional): @@ -214,7 +208,7 @@ class RibbonTableaux(Parent, UniqueRepresentation): REFRENCES: - .. [vanLeeuwen91] Marc. A. A. van Leeuwen *Edge sequences, ribbon tableaux, + .. [vanLeeuwen91] Marc. A. A. van Leeuwen, *Edge sequences, ribbon tableaux, and an action of affine permutations*. Europe J. Combinatorics. **20** (1999). http://wwwmathlabo.univ-poitiers.fr/~maavl/pdf/edgeseqs.pdf """ @@ -815,7 +809,7 @@ def graph_implementation_rec(skp, weight, length, function): class MultiSkewTableau(CombinatorialObject, Element): """ - A multi skew tableau which is a tuple of skew tableau. + A multi skew tableau which is a tuple of skew tableaux. EXAMPLES:: diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 82110716c57..02590fa8e93 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -566,7 +566,7 @@ def weight(self): res = [0] * m for row in self: for i in row: - if not (i is None): + if i > 0 and not (i is None): res[i - 1] += 1 return res diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index dacd4bd7dc3..cc5ce30134f 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1406,7 +1406,8 @@ def weight(self): res = [0] * m for row in self: for i in row: - res[i - 1] += 1 + if i > 0: + res[i - 1] += 1 return res evaluation = weight From 6cd9a20a80d69baf576386a486704dcc62fafacf Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 16:32:24 +0100 Subject: [PATCH 160/665] thanks Nathann, and bye bye stringy hack --- src/sage/combinat/skew_partition.py | 60 ++++++++++++++++++----------- src/sage/combinat/skew_tableau.py | 21 +++++----- src/sage/combinat/tableau.py | 2 - 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index e738c78887d..d0531108c63 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -1019,7 +1019,7 @@ def to_list(self): """ return map(list, list(self)) - def to_dag(self): + def to_dag(self, format="string"): """ Return a directed acyclic graph corresponding to the skew partition ``self``. @@ -1029,6 +1029,12 @@ def to_dag(self): whose edges go from each cell to its lower and right neighbors (in English notation). + INPUT: + + - ``format`` -- either ``'string'`` or ``'tuple'`` (default: + ``'string'``); determines whether the vertices of the + resulting dag will be strings or 2-tuples of coordinates + EXAMPLES:: sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag() @@ -1036,32 +1042,40 @@ def to_dag(self): [('0,1', '0,2', None), ('0,1', '1,1', None)] sage: dag.vertices() ['0,1', '0,2', '1,1', '2,0'] + sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag(format="tuple") + sage: dag.edges() + [((0, 1), (0, 2), None), ((0, 1), (1, 1), None)] + sage: dag.vertices() + [(0, 1), (0, 2), (1, 1), (2, 0)] """ - i = 0 - - #Make the skew tableau from the shape - skew = [[1]*row_length for row_length in self.outer()] - inner = self.inner() - for i in range(len(inner)): - for j in range(inner[i]): - skew[i][j] = None + outer = list(self.outer()) + inner = list(self.inner()) + inner += [0] * (len(outer) - len(inner)) G = DiGraph() - for row in range(len(skew)): - for column in range(len(skew[row])): - if skew[row][column] is not None: - string = "%d,%d" % (row, column) - G.add_vertex(string) - #Check to see if there is a node to the right - if column != len(skew[row]) - 1: - newstring = "%d,%d" % (row, column+1) + for i, outer_i in enumerate(outer): + for j in xrange(inner[i], outer_i): + if format == "string": + string = "%d,%d" % (i, j) + else: + string = (i, j) + G.add_vertex(string) + #Check to see if there is a node to the right + if j != outer_i - 1: + if format == "string": + newstring = "%d,%d" % (i, j + 1) + else: + newstring = (i, j + 1) + G.add_edge(string, newstring) + + #Check to see if there is anything below + if i != len(outer) - 1: + if outer[i+1] > j: + if format == "string": + newstring = "%d,%d" % (i + 1, j) + else: + newstring = (i + 1, j) G.add_edge(string, newstring) - - #Check to see if there is anything below - if row != len(skew) - 1: - if len(skew[row+1]) > column: - newstring = "%d,%d" % (row+1, column) - G.add_edge(string, newstring) return G def quotient(self, k): diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 6ee3a10bff6..1978b428bf3 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -566,7 +566,7 @@ def weight(self): res = [0] * m for row in self: for i in row: - if i > 0 and not (i is None): + if not (i is None) and i > 0: res[i - 1] += 1 return res @@ -1402,25 +1402,24 @@ def is_k_tableau(self, k): return all( kshapes[i+1].contains(kshapes[i]) for i in range(len(shapes)-1) ) -def _label_skew(list, sk): +def _label_skew(list_of_cells, sk): """ - Return a filled-in standard skew tableau given an ordered list - of the coordinates to fill in. + Return a filled-in standard standard skew tableau given an + ordered list ``list_of_cells`` of the coordinates to fill in + (as pairs) and an empty shape ``sk``. EXAMPLES:: sage: import sage.combinat.skew_tableau as skew_tableau - sage: l = [ '0,0', '1,1', '1,0', '0,1' ] + sage: l = [(0, 0), (1, 1), (1, 0), (0, 1)] sage: empty = [[None,None],[None,None]] sage: skew_tableau._label_skew(l, empty) [[1, 4], [3, 2]] """ i = 1 - skew = copy.deepcopy(sk) - for coordstring in list: - coords = coordstring.split(",") - row = int(coords[0]) - column = int(coords[1]) + skew = [list(row) for row in sk] + for coords in list_of_cells: + (row, column) = coords skew[row][column] = i i += 1 return skew @@ -1799,7 +1798,7 @@ def __iter__(self): [[None, 2, 3], [None, 4], [1]], [[None, 2, 4], [None, 3], [1]]] """ - dag = self.skp.to_dag() + dag = self.skp.to_dag(format="tuple") le_list = list(dag.topological_sort_generator()) empty = [[None]*row_length for row_length in self.skp.outer()] diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 66bb1ae4844..78b32aace84 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1575,8 +1575,6 @@ def is_rectangular(self): False sage: Tableau([]).is_rectangular() True - sage: Tableau([[]]).is_rectangular() - True """ if len(self) == 0: return True From 825a53cb28c9e84200295246649af8d8a0e8d989 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 16:40:45 +0100 Subject: [PATCH 161/665] deprecation warning --- src/sage/combinat/combinat.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 53e4b56402c..6ac3b27cf29 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -830,6 +830,11 @@ def __init__(self, l): list and the hash of its parent's class. Thus, each CombinatorialObject should have a unique string representation. + .. WARNING:: + + This class is slowly being deprecated. Use + :class:`~sage.structure.list_clone.ClonableList` instead. + INPUT: - ``l`` - a list or any object that can be convert to a list by From 8577e873851c8ca7789b81f65c450449c1cfd145 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Wed, 18 Mar 2015 10:17:04 +0100 Subject: [PATCH 162/665] Refactor pretty_print/show to use the rich output system --- src/doc/de/tutorial/latex.rst | 1 - .../nf_introduction.rst | 6 +- src/doc/fr/tutorial/latex.rst | 1 - src/doc/pt/tutorial/latex.rst | 1 - src/sage/graphs/generic_graph.py | 15 ++ src/sage/graphs/graph_list.py | 113 +++----- src/sage/misc/all.py | 3 +- src/sage/misc/functional.py | 60 ----- src/sage/misc/latex.py | 61 ----- src/sage/plot/plot.py | 57 ++-- src/sage/repl/all.py | 1 + src/sage/repl/display/fancy_repr.py | 76 ------ src/sage/repl/display/pretty_print.py | 26 -- src/sage/repl/rich_output/__init__.py | 1 + src/sage/repl/rich_output/backend_base.py | 85 +++++- src/sage/repl/rich_output/backend_doctest.py | 9 +- src/sage/repl/rich_output/display_manager.py | 23 +- src/sage/repl/rich_output/output_basic.py | 16 +- src/sage/repl/rich_output/pretty_print.py | 245 ++++++++++++++++++ 19 files changed, 444 insertions(+), 356 deletions(-) create mode 100644 src/sage/repl/rich_output/pretty_print.py diff --git a/src/doc/de/tutorial/latex.rst b/src/doc/de/tutorial/latex.rst index 5fd844e6f0b..aa66b0dc028 100644 --- a/src/doc/de/tutorial/latex.rst +++ b/src/doc/de/tutorial/latex.rst @@ -128,7 +128,6 @@ Kapitel :ref:`sec-custom-generation` dargestellt. Der interne ``pretty_print()`` Befehl zeigt die Konvertierung von Sage Objekten in HTML Code der MathJax nutzt im Notebook. :: - sage: from sage.misc.latex import pretty_print sage: pretty_print(x^12) sage: pretty_print(integrate(sin(x), x)) diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_introduction.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_introduction.rst index 397c4cf530b..554b8a1ae7b 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_introduction.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_introduction.rst @@ -274,15 +274,15 @@ it to the variable ``a``. Viewing complicated symbolic expressions ---------------------------------------- -To see the solution nicely typeset, use the ``show`` +To see the solution nicely typeset, use the ``pretty_print`` command .. link :: - sage: show(a) - -\frac{1}{2} ... + sage: pretty_print(a) + sage: pretty_print(integrate(sin(x), x)) diff --git a/src/doc/pt/tutorial/latex.rst b/src/doc/pt/tutorial/latex.rst index 70ebcd4c3bb..62298ae6cf0 100644 --- a/src/doc/pt/tutorial/latex.rst +++ b/src/doc/pt/tutorial/latex.rst @@ -132,7 +132,6 @@ esse processo é discutido abaixo na seção O comando interno ``pretty_print()`` ilustra a conversão de objetos do Sage para HTML que emprega o MathJax no Notebook. :: - sage: from sage.misc.latex import pretty_print sage: pretty_print(x^12) sage: pretty_print(integrate(sin(x), x)) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ef9cbc7e562..fe538e917aa 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15393,6 +15393,21 @@ def graphplot(self, **options): from sage.graphs.graph_plot import GraphPlot return GraphPlot(graph=self, options=options) + def _rich_repr_(self, display_manager, **kwds): + """ + Rich Output Magic Method + + See :mod:`sage.repl.rich_output` for details. + + EXAMPLES:: + + sage: from sage.repl.rich_output import get_display_manager + sage: dm = get_display_manager() + sage: Graph()._rich_repr_(dm, edge_labels=True) + OutputImagePng container + """ + return self.plot(**kwds)._rich_repr_(display_manager) + @options() def plot(self, **options): r""" diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index e70cc6c03e9..dca963e38a5 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -239,21 +239,18 @@ def to_sparse6(list, file = None, output_list=False): file.write(l) file.flush() -def to_graphics_arrays(list, **kwds): + +def to_graphics_array(graph_list, **kwds): """ - Returns a list of Sage graphics arrays containing the graphs in - list. The maximum number of graphs per array is 20 (5 rows of 4). - Use this function if there are too many graphs for the show_graphs - function. The graphics arrays will contain 20 graphs each except - potentially the last graphics array in the list. + Draw all graphs in a graphics array INPUT: + - ``graph_list`` - a list of Sage graphs - - ``list`` - a list of Sage graphs - + GRAPH PLOTTING: - GRAPH PLOTTING: Defaults to circular layout for graphs. This allows + Defaults to circular layout for graphs. This allows for a nicer display in a small area and takes much less time to compute than the spring- layout algorithm for many graphs. @@ -261,44 +258,27 @@ def to_graphics_arrays(list, **kwds): sage: glist = [] sage: for i in range(999): - ... glist.append(graphs.RandomGNP(6,.45)) - ... - sage: garray = graphs_list.to_graphics_arrays(glist) - - Display the first graphics array in the list. - - :: - - sage: garray[0].show() - - Display the last graphics array in the list. - - :: - - sage: garray[len(garray)-1].show() + ....: glist.append(graphs.RandomGNP(6,.45)) + sage: garray = graphs_list.to_graphics_array(glist) + sage: garray.nrows(), garray.ncols() + (250, 4) See the .plot() or .show() documentation for an individual graph - for options, all of which are available from to_graphics_arrays - - :: + for options, all of which are available from + :func:`to_graphics_array`:: sage: glist = [] sage: for _ in range(10): ... glist.append(graphs.RandomLobster(41, .3, .4)) - sage: w = graphs_list.to_graphics_arrays(glist, layout='spring', vertex_size=20) - sage: len(w) - 1 - sage: w[0] + sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) Graphics Array of size 3 x 4 """ - from sage.plot.plot import graphics_array from sage.graphs import graph plist = [] - g_arrays = [] - for i in range (len(list)): - if ( isinstance( list[i], graph.GenericGraph ) ): - pos = list[i].get_pos() - if ( pos is None ): + for i in range(len(graph_list)): + if isinstance(graph_list[i], graph.GenericGraph): + pos = graph_list[i].get_pos() + if pos is None: if 'layout' not in kwds: kwds['layout'] = 'circular' if 'vertex_size' not in kwds: @@ -306,39 +286,16 @@ def to_graphics_arrays(list, **kwds): if 'vertex_labels' not in kwds: kwds['vertex_labels'] = False kwds['graph_border'] = True - plist.append(list[i].plot(**kwds)) - else: plist.append(list[i].plot(pos=pos, vertex_size=50, vertex_labels=False, graph_border=True)) - else: raise TypeError('Param list must be a list of Sage (di)graphs.') - - num_arrays = len(plist) // 20 - if ( len(plist)%20 > 0 ): num_arrays += 1 - rows = 5 - cols = 4 - - for i in range (num_arrays-1): - glist = [] - for j in range (rows*cols): - glist.append(plist[ i*rows*cols + j ]) - ga = graphics_array(glist, rows, cols) - ga._set_figsize_([8,10]) - g_arrays.append(ga) - - last = len(plist)%20 - if ( last == 0 and len(plist) != 0 ): last = 20 - index = (num_arrays-1)*rows*cols - last_rows = last/cols - if ( last%cols > 0 ): last_rows += 1 - - glist = [] - for i in range (last): - glist.append(plist[ i + index]) - ga = graphics_array(glist, last_rows, cols) - ga._set_figsize_([8, 2*last_rows]) - g_arrays.append(ga) - - return g_arrays - -def show_graphs(list, **kwds): + plist.append(graph_list[i].plot(**kwds)) + else: + plist.append(graph_list[i].plot(pos=pos, vertex_size=50, vertex_labels=False, graph_border=True)) + else: + raise TypeError('param list must be a list of Sage (di)graphs.') + from sage.plot.plot import graphics_array + return graphics_array(plist, ncols=4) + + +def show_graphs(graph_list, **kwds): """ Shows a maximum of 20 graphs from list in a sage graphics array. If more than 20 graphs are given in the list argument, then it will @@ -395,20 +352,18 @@ def show_graphs(list, **kwds): sage: graphs_list.show_graphs(g) See the .plot() or .show() documentation for an individual graph - for options, all of which are available from to_graphics_arrays - - :: + for options, all of which are available from + :func:`to_graphics_array`:: sage: glist = [] sage: for _ in range(10): - ... glist.append(graphs.RandomLobster(41, .3, .4)) + ....: glist.append(graphs.RandomLobster(41, .3, .4)) sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) """ - ga_list = to_graphics_arrays(list, **kwds) - - for i in range (len(ga_list)): - (ga_list[i]).show() + graph_list = list(graph_list) + for i in range(len(graph_list) // 20 + 1): + graph_slice =graph_list[20*i:20*(i+1)] + to_graphics_array(graph_slice, **kwds).show() - return diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 755fbd7f47b..9008f3436ee 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -136,7 +136,6 @@ round, quotient, quo, - show, isqrt, squarefree_part, symbolic_sum as sum, @@ -144,7 +143,7 @@ zero) -from latex import LatexExpr, latex, view, pretty_print, pretty_print_default +from latex import LatexExpr, latex, view, pretty_print_default from trace import trace diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index e8d634704b5..60afb9ae1e2 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -1517,66 +1517,6 @@ def quotient(x, y, *args, **kwds): quo = quotient -def show(x, *args, **kwds): - r""" - Show a graphics object x. - - For additional ways to show objects in the notebook, look - at the methods on the html object. For example, - html.table will produce an HTML table from a nested - list. - - - OPTIONAL INPUT: - - - - ``filename`` - (default: None) string - - - SOME OF THESE MAY APPLY: - - - ``dpi`` - dots per inch - - - ``figsize``- [width, height] (same for square aspect) - - - ``axes`` - (default: True) - - - ``fontsize`` - positive integer - - - ``frame`` - (default: False) draw a MATLAB-like frame around the - image - - EXAMPLES:: - - sage: show(graphs(3)) - sage: show(list(graphs(3))) - """ - if not isinstance(x, (sage.interfaces.expect.Expect, sage.interfaces.expect.ExpectElement)): - try: - return x.show(*args, **kwds) - except AttributeError: - pass - if isinstance(x, sage.interfaces.mathematica.MathematicaElement): - return x.show(*args, **kwds) - - import types - if isinstance(x, types.GeneratorType): - x = list(x) - if isinstance(x, list): - if len(x) > 0: - from sage.graphs.graph import GenericGraph - if isinstance(x[0], GenericGraph): - import sage.graphs.graph_list as graphs_list - graphs_list.show_graphs(x) - return - _do_show(x) - -def _do_show(x): - if sage.doctest.DOCTEST_MODE: - return sage.misc.latex.latex(x) - from latex import view - view(x, mode='display') - def isqrt(x): """ diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 00e85c9073c..80de0c32b7f 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -2399,67 +2399,6 @@ def print_or_typeset(object): else: print(object) -def pretty_print (*args): - r""" - Try to pretty print the arguments in an intelligent way. For graphics - objects, this returns their default representation. For other - objects, in the notebook, this calls the :func:`view` command, - while from the command line, this produces an html string suitable - for processing by MathJax. - - INPUT: - - - ``objects`` -- The input can be any Sage object, a list or tuple of - Sage objects, or Sage objects passed in as separate arguments. - - This function is used in the notebook when the "Typeset" button is - checked. - - EXAMPLES:: - - sage: pretty_print(ZZ) # indirect doctest - - sage: pretty_print("Integers = ", ZZ) # trac 11775 - - - To typeset LaTeX code as-is, use :class:`LatexExpr`:: - - sage: pretty_print(LatexExpr(r"\frac{x^2 + 1}{x - 2}")) - - """ - # view s if it is not empty. Used twice. - def _show_s(s): - if s != []: - if EMBEDDED_MODE: - view(tuple(s), combine_all=True) - else: - print(MathJax().eval(tuple(s), mode='inline', - combine_all=True)) - - import __builtin__ - in_ipython = hasattr(__builtin__, 'get_ipython') - s = [] - for object in args: - if object is None: - continue - if in_ipython: - get_ipython().displayhook.update_user_ns(object) - else: - __builtin__._ = object - - from sage.plot.plot import Graphics - from sage.plot.plot3d.base import Graphics3d - if isinstance(object, (Graphics, Graphics3d)): - _show_s(s) - s = [] - print(repr(object)) - - else: - s.append(object) - - _show_s(s) - return - def pretty_print_default(enable=True): r""" Enable or disable default pretty printing. Pretty printing means diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index ccf6ce73f0f..85e144d963c 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2364,6 +2364,7 @@ def reshape(v, n, m): # Now v should be a single list. # First, make it have the right length. + v = list(v) # do not mutate the argument for i in xrange(n*m - len(v)): v.append(G) @@ -2379,20 +2380,21 @@ def reshape(v, n, m): return L -def graphics_array(array, n=None, m=None): +def graphics_array(array, nrows=None, ncols=None): r""" ``graphics_array`` take a list of lists (or tuples) of graphics objects and plots them all on one canvas (single plot). INPUT: - - ``array`` - a list of lists or tuples - - - ``n, m`` - (optional) integers - if n and m are - given then the input array is flattened and turned into an n x m - array, with blank graphics objects padded at the end, if - necessary. + - ``array`` -- a list of lists or tuples. The graphics objects to + combine into a graphics array. + - ``nrows, ncols`` -- (optional) integers. If both are given then + the input array is flattened and turned into an ``nrows`` x + ``ncols`` array, with blank graphics objects padded at the end, + if necessary. If only one is specified, the other is chosen + automatically. EXAMPLE: Make some plots of `\sin` functions:: @@ -2429,20 +2431,41 @@ def graphics_array(array, n=None, m=None): sage: L = [plot(sin(k*x),(x,-pi,pi)) for k in [1..3]] sage: G = graphics_array(L) sage: G.show(figsize=[5,3]) # smallish and compact - - :: - sage: G.show(figsize=[10,20]) # bigger and tall and thin; long time (2s on sage.math, 2012) + sage: G.show(figsize=8) # figure as a whole is a square - :: + Specifying only the number of rows or the number of columns + computes the other dimension automatically:: - sage: G.show(figsize=8) # figure as a whole is a square + sage: ga = graphics_array([plot(sin)] * 10, nrows=3) + sage: ga.nrows(), ga.ncols() + (3, 4) + sage: ga = graphics_array([plot(sin)] * 10, ncols=3) + sage: ga.nrows(), ga.ncols() + (4, 3) """ - if not n is None: - # Flatten then reshape input - n = int(n) - m = int(m) - array = reshape(array, n, m) + # TODO: refactor the whole array flattening and reshaping into a class + if nrows is None and ncols is None: + pass + elif nrows is not None and ncols is not None: + nrows = int(nrows) + ncols = int(ncols) + array = reshape(array, nrows, ncols) + else: + # nrows is None xor ncols is None + if len(array) > 0 and isinstance(array[0], Graphics): + length = len(array) + else: + length = sum(map(len, array)) + if nrows is None: + ncols = int(ncols) + nrows = length // ncols + 1 + elif ncols is None: + nrows = int(nrows) + ncols = length // nrows + 1 + else: + assert False + array = reshape(array, nrows, ncols) return GraphicsArray(array) def var_and_list_of_values(v, plot_points): diff --git a/src/sage/repl/all.py b/src/sage/repl/all.py index 9367bfc5b4c..81f1ea9a105 100644 --- a/src/sage/repl/all.py +++ b/src/sage/repl/all.py @@ -7,3 +7,4 @@ 'attach', 'detach', 'attached_files', 'load_attach_path', 'reset_load_attach_path', 'load_attach_mode']) +from sage.repl.rich_output.pretty_print import pretty_print, show diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index 1658cb291a2..5c1aa6977fa 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -287,82 +287,6 @@ def __call__(self, obj, p, cycle): return True -class AsciiArtRepr(ObjectReprABC): - """ - Ascii Art representation - - .. automethod:: __call__ - """ - - def __call__(self, obj, p, cycle): - r""" - Return ascii art format. - - INPUT: - - - ``obj`` -- anything. Object to format. - - - ``p`` -- PrettyPrinter instance. - - - ``cycle`` -- boolean. Whether there is a cycle. - - OUTPUT: - - Boolean. Whether the representer is applicable to ``obj``. If - ``True``, the string representation is appended to ``p``. - - EXAMPLES:: - - sage: from sage.repl.display.fancy_repr import AsciiArtRepr - sage: pp = AsciiArtRepr() - sage: pp.format_string(x/2) - 'x\n-\n2' - """ - from sage.misc.ascii_art import ascii_art - output = ascii_art(obj) - p.text(output) - return True - - -class TypesetRepr(ObjectReprABC): - """ - Typeset representation - - .. automethod:: __call__ - """ - - def __call__(self, obj, p, cycle): - r""" - Return typeset format. - - INPUT: - - - ``obj`` -- anything. Object to format. - - - ``p`` -- PrettyPrinter instance. - - - ``cycle`` -- boolean. Whether there is a cycle. - - OUTPUT: - - Boolean. Whether the representer is applicable to ``obj``. If - ``True``, the string representation is appended to ``p``. - - EXAMPLES:: - - sage: from sage.repl.display.fancy_repr import TypesetRepr - sage: pp = TypesetRepr() - sage: pp.format_string(x/2) - - '' - """ - # We should probably return that as string, but - # latex.pretty_print doesn't give us a useful interface - from sage.misc.latex import pretty_print - pretty_print(obj) - return True - - class TallListRepr(ObjectReprABC): """ Special representation for lists with tall entries (e.g. matrices) diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index 3648b40efc2..ff3aebcefea 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -156,29 +156,3 @@ def pretty(self, obj): self.end_group() self.stack.pop() - - -class AsciiArtPrettyPrinter(SagePrettyPrinter): - """ - Pretty printer returning ASCII art - """ - - pretty_repr = ( - AsciiArtRepr(), - ) + SagePrettyPrinter.pretty_repr - - -class TypesetPrettyPrinter(SagePrettyPrinter): - """ - Pretty printer returning typeset html - - This is also used in the emacs-mode. - """ - - pretty_repr = ( - TypesetRepr(), - ) + SagePrettyPrinter.pretty_repr - - - - diff --git a/src/sage/repl/rich_output/__init__.py b/src/sage/repl/rich_output/__init__.py index 5b028cd9cd7..ad29d0d3705 100644 --- a/src/sage/repl/rich_output/__init__.py +++ b/src/sage/repl/rich_output/__init__.py @@ -1,5 +1,6 @@ # -*- encoding: utf-8 -*- from .display_manager import get_display_manager +from .pretty_print import pretty_print diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index 7f4f127621e..d9e1fe4c610 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -250,7 +250,7 @@ def _apply_pretty_printer(self, pretty_printer_class, obj): printer.flush() return stream.getvalue() - def plain_text_formatter(self, obj): + def plain_text_formatter(self, obj, **kwds): r""" Hook to override how plain text is being formatted. @@ -263,6 +263,14 @@ def plain_text_formatter(self, obj): - ``obj`` -- anything. + - ``**kwds`` -- optional keyword arguments to control the + formatting. Supported are: + + * ``concatenate`` -- boolean (default: ``False``). If + ``True``, the argument ``obj`` must be iterable and its + entries will be concatenated. There is a single + whitespace between entries. + OUTPUT: Instance of @@ -283,20 +291,36 @@ def plain_text_formatter(self, obj): 10,\n 11,\n 12,\n 13,\n 14,\n 15,\n 16,\n 17,\n 18,\n 19,\n 20,\n 21,\n 22,\n 23,\n 24,\n 25,\n 26,\n 27,\n 28,\n 29]' - """ + + sage: out = backend.plain_text_formatter(range(20), concatenate=True) + sage: out.text.get() + '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19' + """ from sage.repl.display.pretty_print import SagePrettyPrinter - plain_text = self._apply_pretty_printer(SagePrettyPrinter, obj) + if kwds.get('concatenate', False): + plain_text = ' '.join( + self._apply_pretty_printer(SagePrettyPrinter, o) for o in obj) + else: + plain_text = self._apply_pretty_printer(SagePrettyPrinter, obj) from sage.repl.rich_output.output_basic import OutputPlainText return OutputPlainText(plain_text) - def ascii_art_formatter(self, obj): - """ + def ascii_art_formatter(self, obj, **kwds): + r""" Hook to override how ascii art is being formatted. INPUT: - ``obj`` -- anything. + - ``**kwds`` -- optional keyword arguments to control the + formatting. Supported are: + + * ``concatenate`` -- boolean (default: ``False``). If + ``True``, the argument ``obj`` must be iterable and its + entries will be concatenated. There is a single + whitespace between entries. + OUTPUT: Instance of @@ -318,13 +342,25 @@ def ascii_art_formatter(self, obj): ] 22, 23, 24, 25, 26, 27, 28, 29 ] - """ - from sage.repl.display.pretty_print import AsciiArtPrettyPrinter - ascii_art = self._apply_pretty_printer(AsciiArtPrettyPrinter, obj) + + sage: backend.ascii_art_formatter([1,2,3], concatenate=False).ascii_art.get() + '[ ]\n[ 1, 2, 3 ]' + sage: backend.ascii_art_formatter([1,2,3], concatenate=True ).ascii_art.get() + '1 2 3' + """ + from sage.misc.ascii_art import ascii_art, empty_ascii_art + if kwds.get('concatenate', False): + result = empty_ascii_art + for o in obj: + if result is not empty_ascii_art: + result += ascii_art(' ') + result += ascii_art(o) + else: + result = ascii_art(obj) from sage.repl.rich_output.output_basic import OutputAsciiArt - return OutputAsciiArt(ascii_art) + return OutputAsciiArt(str(result)) - def latex_formatter(self, obj): + def latex_formatter(self, obj, **kwds): r""" Hook to override how Latex is being formatted. @@ -332,6 +368,14 @@ def latex_formatter(self, obj): - ``obj`` -- anything. + - ``**kwds`` -- optional keyword arguments to control the + formatting. Supported are: + + * ``concatenate`` -- boolean (default: ``False``). If + ``True``, the argument ``obj`` must be iterable and its + entries will be concatenated. There is a single + whitespace between entries. + OUTPUT: Instance of @@ -351,9 +395,28 @@ def latex_formatter(self, obj): '\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{1}{2}' sage: out.mathjax() '' + + sage: out = backend.latex_formatter([1/2, x, 3/4, ZZ], concatenate=False) + sage: out.latex.get() + '\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left[\\frac{1}{2}, x, \\frac{3}{4}, \\Bold{Z}\\right]' + sage: out = backend.latex_formatter([1/2, x, 3/4, ZZ], concatenate=True) + sage: out.latex.get() + '\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\frac{1}{2} x \\frac{3}{4} \\Bold{Z}' + + TESTS:: + + sage: backend.latex_formatter([], concatenate=False).latex.get() + '\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left[\\right]' + sage: backend.latex_formatter([], concatenate=True).latex.get() + '\\newcommand{\\Bold}[1]{\\mathbf{#1}}' """ + concatenate = kwds.get('concatenate', False) from sage.misc.latex import MathJax - mathjax = MathJax().eval(obj, mode='plain', combine_all=True) + if concatenate: + obj = tuple(obj) # MathJax treats tuples special + mathjax = MathJax().eval(obj, mode='plain', combine_all=True) + else: + mathjax = MathJax().eval(obj, mode='plain', combine_all=False) from sage.repl.rich_output.output_basic import OutputLatex return OutputLatex(str(mathjax)) diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index 3689a7fb828..c585ffa17d4 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -146,8 +146,8 @@ def displayhook(self, plain_text, rich_output): Graphics object consisting of 1 graphics primitive """ self.validate(rich_output) - if any(isinstance(rich_output, cls) for cls in - [OutputPlainText, OutputAsciiArt, OutputLatex]): + if any(isinstance(rich_output, cls) + for cls in [OutputPlainText, OutputAsciiArt, OutputLatex]): rich_output.print_to_stdout() else: plain_text.print_to_stdout() @@ -179,8 +179,9 @@ def display_immediately(self, plain_text, rich_output): sage: dm.display_immediately(plt) # indirect doctest """ self.validate(rich_output) - if any(isinstance(rich_output, cls) for cls in - [OutputPlainText, OutputAsciiArt, OutputLatex]): + if isinstance(rich_output, OutputLatex): + print(rich_output.mathjax(display=False)) + elif any(isinstance(rich_output, cls) for cls in [OutputPlainText, OutputAsciiArt]): rich_output.print_to_stdout() def validate(self, rich_output): diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index 92f6868ffa7..b9b8a02b927 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -430,13 +430,13 @@ def _promote_output(self, output): output.__class__ = specialized_class return output - def _preferred_text_formatter(self, obj, plain_text=None): + def _preferred_text_formatter(self, obj, plain_text=None, **kwds): """ Return the preferred textual representation INPUT: - - ``obj`` -- anything. + - ``obj`` -- anything. The objects to format. - ``plain_text`` -- ``None`` (default) or string. The plain text representation. If specified, this will be used for @@ -458,19 +458,19 @@ def _preferred_text_formatter(self, obj, plain_text=None): sage: dm = get_display_manager() sage: dm.preferences.text is None True - sage: dm._preferred_text_formatter(1/42) + sage: dm._preferred_text_formatter([1/42]) OutputPlainText container sage: dm.preferences.text = 'plain' - sage: dm._preferred_text_formatter(1/42) + sage: dm._preferred_text_formatter([1/42]) OutputPlainText container sage: dm.preferences.text = 'ascii_art' - sage: dm._preferred_text_formatter(1/42) + sage: dm._preferred_text_formatter([1/42]) OutputAsciiArt container sage: dm.preferences.text = 'latex' - sage: dm._preferred_text_formatter(1/42) + sage: dm._preferred_text_formatter([1/42]) \newcommand{\Bold}[1]{\mathbf{#1}}\verb|OutputLatex|\phantom{\verb!x!}\verb|container| sage: del dm.preferences.text # reset to default @@ -478,12 +478,12 @@ def _preferred_text_formatter(self, obj, plain_text=None): want = self.preferences.text supported = self._backend.supported_output() if want == 'ascii_art' and OutputAsciiArt in supported: - out = self._backend.ascii_art_formatter(obj) + out = self._backend.ascii_art_formatter(obj, **kwds) if type(out) != OutputAsciiArt: raise OutputTypeException('backend returned wrong output type, require AsciiArt') return out if want == 'latex' and OutputLatex in supported: - out = self._backend.latex_formatter(obj) + out = self._backend.latex_formatter(obj, **kwds) if type(out) != OutputLatex: raise OutputTypeException('backend returned wrong output type, require Latex') return out @@ -491,7 +491,7 @@ def _preferred_text_formatter(self, obj, plain_text=None): if type(plain_text) != OutputPlainText: raise OutputTypeException('backend returned wrong output type, require PlainText') return plain_text - out = self._backend.plain_text_formatter(obj) + out = self._backend.plain_text_formatter(obj, **kwds) if type(out) != OutputPlainText: raise OutputTypeException('backend returned wrong output type, require PlainText') return out @@ -578,9 +578,10 @@ def _rich_output_formatter(self, obj, rich_repr_kwds): with restricted_output(self, [OutputPlainText]): plain_text = self._call_rich_repr(obj, rich_repr_kwds) if plain_text is None: - plain_text = self._backend.plain_text_formatter(obj) + plain_text = self._backend.plain_text_formatter(obj, **rich_repr_kwds) if rich_output is None: - rich_output = self._preferred_text_formatter(obj, plain_text=plain_text) + rich_output = self._preferred_text_formatter( + obj, plain_text=plain_text, **rich_repr_kwds) # promote output container types to backend-specific containers plain_text = self._promote_output(plain_text) rich_output = self._promote_output(rich_output) diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index f445071ee53..dd01012f84a 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -251,10 +251,15 @@ def __init__(self, latex): """ self.latex = OutputBuffer(latex) - def mathjax(self): + def mathjax(self, display=True): r""" Return the LaTeX with a surrounding MathJax HTML code. + INPUT: + + - ``display`` -- boolean. Whether to return display (as + opposed to inline) TeX. + EXAMPLES:: sage: from sage.repl.rich_output.output_catalog import OutputLatex @@ -265,9 +270,14 @@ def mathjax(self): '1' sage: rich_output.mathjax() '' + sage: rich_output.mathjax(display=False) + '' """ - return r''.format( - self.latex.get()) + if display: + template = r'' + else: + template = r'' + return template.format(self.latex.get()) def display_equation(self): r""" diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py new file mode 100644 index 00000000000..6ec008cc9bd --- /dev/null +++ b/src/sage/repl/rich_output/pretty_print.py @@ -0,0 +1,245 @@ +# -*- encoding: utf-8 -*- +""" +The ``pretty_print`` command. + +Works similar to the ``print`` function, except that it always tries +to use a rich output for an object. Only if that is not available it +is falling back on the plain text. + +EXAMPLES:: + + sage: pretty_print(1, 2, 3) + + +Printing a graphics object just prints a string, whereas +:func:`pretty_print` does not print anything and just shows the +graphics instead:: + + sage: print(plot(sin)) + Graphics object consisting of 1 graphics primitive + sage: pretty_print(plot(sin)) +""" + + +#***************************************************************************** +# Copyright (C) 2015 Volker Braun +# +# 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/ +#***************************************************************************** + + +import types +import collections + +from sage.structure.sage_object import SageObject +from sage.repl.rich_output import get_display_manager + + +class SequencePrettyPrinter(SageObject): + + def __init__(self, *args, **kwds): + """ + Pretty Printer for Muliple Arguments. + + INPUT/OUTPUT: + + Same as :func:`pretty_print`, except that the number of + arguments must be >= 2. Otherwise its not a sequence of things + to print. + + EXAMPLES:: + + sage: pretty_print(1, 2, 3) # indirect doctest + + sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter + sage: SequencePrettyPrinter(1, 2, 3).pretty_print() + 1 2 3 + """ + self.args = args + assert len(self.args) >= 2 + self.kwds = kwds + + def is_homogeneous(self, common_type): + """ + Return whether the pretty print items are homogeneous + + INPUT: + + - ``common_type`` -- a type. + + OUTPUT: + + Boolean. Whether all items to be pretty printed are of said + type. + + EXAMPLES:: + + sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter + sage: seq = SequencePrettyPrinter(1, 2, 3) + sage: seq.is_homogeneous(Integer) + True + sage: seq.is_homogeneous(str) + False + """ + return all(isinstance(arg, common_type) for arg in self.args) + + def _concatenate_graphs(self): + """ + Plot multiple graphs into a single plot + + OUTPUT: + + A graphics object. + + EXAMPLES:: + + sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter + sage: plt = SequencePrettyPrinter(*list(graphs(3)))._concatenate_graphs() + sage: type(plt) + + sage: plt + Graphics Array of size 2 x 4 + """ + import sage.graphs.graph_list as graphs_list + return graphs_list.to_graphics_array(self.args, **self.kwds) + + def _concatenate_graphics(self): + """ + Combine multiple graphics objects into one graphics array + + OUTPUT: + + A graphics array. + + EXAMPLES:: + + sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter + sage: ga = SequencePrettyPrinter(*[Graphics()]*5)._concatenate_graphics() + sage: type(ga) + + sage: ga.nrows(), ga.ncols() + (2, 4) + """ + from sage.plot.plot import graphics_array + return graphics_array(self.args, ncols=4, **self.kwds) + + def pretty_print(self): + """ + Actually do the pretty print. + + EXAMPLES:: + + sage: from sage.repl.rich_output.pretty_print import SequencePrettyPrinter + sage: SequencePrettyPrinter(1, 2, 3).pretty_print() + 1 2 3 + + The keyword arguments are only used the first time graphics + output is generated:: + + sage: seq = SequencePrettyPrinter(Graph(), Graph(), edge_labels=True) + sage: seq.pretty_print() # does not pass edge_labels to graphics object + sage: seq._concatenate_graphs().show(edge_labels=True) + Traceback (most recent call last): + ... + TypeError: matplotlib() got an unexpected keyword argument 'edge_labels' + """ + from sage.plot.plot import Graphics + from sage.graphs.graph import GenericGraph + if self.is_homogeneous(GenericGraph): + args = self._concatenate_graphs() + kwds = dict() + elif self.is_homogeneous(Graphics): + args = self._concatenate_graphics() + kwds = dict() + else: + args = self.args + kwds = dict(self.kwds) + kwds['concatenate'] = True + get_display_manager().display_immediately(args, **kwds) + + +def pretty_print(*args, **kwds): + r""" + Pretty print the arguments in an intelligent way. + + For a single positional argument, this function chooses the + highest-quality output supported by the user interface. + + For certain homogeneous multiple positional arguments a suitable + combined graphical output is generated. In particular, graphs and + plots are treated special. + + Otherwise this function will concatenate the textual + representations. Latex output is preferred if none is specified + via + :meth:`~sage.repl.rich_output.display_manager.DisplayManager.preferences`. + + INPUT: + + - ``*args`` -- any number of positional arguments. The objects to + pretty print. If the single argument is an iterator/generator + then it is expanded. + + - ``**kwds`` -- optional keyword arguments that are passed to the + rich representation. Examples include: + + - ``dpi`` - dots per inch + + - ``figsize``- [width, height] (same for square aspect) + + - ``axes`` - (default: True) + + - ``fontsize`` - positive integer + + - ``frame`` - (default: False) draw a MATLAB-like frame around + the image + + EXAMPLES:: + + sage: pretty_print(ZZ) + + + sage: pretty_print("Integers = ", ZZ) # trac 11775 + + + To typeset LaTeX code as-is, use :class:`LatexExpr`:: + + sage: pretty_print(LatexExpr(r"\frac{x^2 + 1}{x - 2}")) + + + Iterators and generators are unwrapped:: + + sage: iterator = iter(range(3)); iterator + + sage: pretty_print(iterator) + + + TESTS:: + + sage: plt = plot(sin) + sage: pretty_print(plt) # graphics output + sage: pretty_print(ZZ, 123, plt) # latex output + + sage: pretty_print(plt, plt) # graphics output + """ + if len(args) == 1 and isinstance(args[0], (types.GeneratorType, collections.Iterator)): + args = tuple(args[0]) + dm = get_display_manager() + old_preferences_text = dm.preferences.text + try: + if dm.preferences.text is None: + dm.preferences.text = 'latex' + if len(args) == 0: + pass + elif len(args) == 1: + dm.display_immediately(*args, **kwds) + else: + SequencePrettyPrinter(*args, **kwds).pretty_print() + finally: + dm.preferences.text = old_preferences_text + + +show = pretty_print From 42f4985c93ebf3afb3772ad2298673ba1db372da Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 21 Mar 2015 17:08:11 +0100 Subject: [PATCH 163/665] remove the unused and broken print_or_typeset --- src/sage/misc/latex.py | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 80de0c32b7f..c13324ba786 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -2368,36 +2368,6 @@ def repr_lincomb(symbols, coeffs): s = s.replace("+ -","- ") return s -def print_or_typeset(object): - r""" - 'view' or 'print' the object depending on the situation. - - In particular, if in notebook mode with the typeset box checked, - view the object. Otherwise, print the object. - - INPUT: - - - ``object`` -- Anything - - EXAMPLES:: - - sage: sage.misc.latex.print_or_typeset(3) - 3 - sage: sage.misc.latex.EMBEDDED_MODE=True - sage: sage.misc.latex.print_or_typeset(3) - 3 - sage: TEMP = sys.displayhook - sage: sys.displayhook = sage.misc.latex.pretty_print - sage: sage.misc.latex.print_or_typeset(3) - - sage: sage.misc.latex.EMBEDDED_MODE=False - sage: sys.displayhook = TEMP - """ - import sys - if EMBEDDED_MODE and sys.displayhook == pretty_print: - view(object) - else: - print(object) def pretty_print_default(enable=True): r""" From 7b07c7a57bad9f3644c88c7f3f875008d6d3ec98 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 21 Mar 2015 17:57:15 +0100 Subject: [PATCH 164/665] trac #17464: Merge and package version update --- build/pkgs/bliss/package-version.txt | 2 +- src/sage/graphs/bliss.pyx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/bliss/package-version.txt b/build/pkgs/bliss/package-version.txt index b214dd991b6..615e437dd31 100644 --- a/build/pkgs/bliss/package-version.txt +++ b/build/pkgs/bliss/package-version.txt @@ -1 +1 @@ -0.72 +0.72.p1 diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 1871b47db73..78db48a0b19 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -21,6 +21,7 @@ AUTHORS: include "sage/ext/interrupt.pxi" include 'sage/ext/stdsage.pxi' include 'sage/ext/cdefs.pxi' +from cpython cimport PyObject cdef extern from "graph.hh" namespace "bliss": From 7a51bbe10807f2cf53a0e0cb7715444628344a14 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sat, 21 Mar 2015 19:54:48 +0100 Subject: [PATCH 165/665] fix for issue pointed out in #18018 + microoptimization for standard_descents --- src/sage/combinat/tableau.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 78b32aace84..9673c27d2bb 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -1710,7 +1710,7 @@ def leq(self, secondtab): True """ if not secondtab in Tableaux(): - raise TypeError(secondtab + " must be a tableau") + raise TypeError(str(secondtab) + " must be a tableau") sh = self.shape() if sh != secondtab.shape(): raise TypeError("the tableaux must be the same shape") @@ -1718,13 +1718,13 @@ def leq(self, secondtab): for b in xrange(len(self[a])) ) def k_weight(self, k): - """ + r""" Return the `k`-weight of ``self``. - A tableau has `k`-weight `alpha=(alpha_1,...,alpha_n)` if there - are exactly `alpha_i` distinct residues for the cells occupied - by the letter `i` for each `i`. The residue of a cell in - position `(a,b)` is `a-b` modulo `k+1`. + A tableau has `k`-weight `\alpha = (\alpha_1, ..., \alpha_n)` + if there are exactly `\alpha_i` distinct residues for the + cells occupied by the letter `i` for each `i`. The residue + of a cell in position `(a,b)` is `a-b` modulo `k+1`. This definition is the one used in [Ive2012]_ (p. 12). @@ -1732,12 +1732,12 @@ def k_weight(self, k): .. [Ive2012] S. Iveson, *Tableaux on `k + 1`-cores, reduced words for affine - permutations, and `k`-Schur expansions*, + permutations, and `k`-Schur expansions*, Operators on `k`-tableaux and the `k`-Littlewood-Richardson rule for a special case, UC Berkeley: Mathematics, Ph.D. Thesis, https://escholarship.org/uc/item/7pd1v1b5 - + EXAMPLES:: sage: Tableau([[1,2],[2,3]]).k_weight(1) @@ -1765,7 +1765,7 @@ def k_weight(self, k): #If there are no elements that meet the condition if new_s == []: - res .append(0) + res.append(0) continue x = uniq([ (i-j)%(k+1) for i,j in new_s ]) res.append(len(x)) @@ -3908,10 +3908,10 @@ def standard_descents(self): for i in range(1, whatpart): #find out what row i and i+1 are in (we're using the #standardness of self here) - for j in range(len(self)): - if self[j].count(i+1) > 0: + for row in self: + if row.count(i+1) > 0: break - if self[j].count(i) > 0: + if row.count(i) > 0: descents.append(i) break return descents From 70e4d3af7d4f26e4cf7fca155ccfe12193e6dae4 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 21 Mar 2015 20:59:06 +0100 Subject: [PATCH 166/665] fix doctest in symbolic expression show() --- src/sage/symbolic/expression.pyx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 77aea5ad9df..d0e7d30f268 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -10305,15 +10305,22 @@ cdef class Expression(CommutativeRingElement): def show(self): """ - Show this symbolic expression, i.e., typeset it nicely. + Pretty-Print this symbolic expression + + This typeset it nicely and prints it immediately. + + OUTPUT: + + This method does not return anything. Like ``print``, output + is sent directly to the screen. EXAMPLES:: sage: (x^2 + 1).show() - x^{2} + 1 + """ - from sage.misc.functional import _do_show - return _do_show(self) + from sage.repl.rich_output.pretty_print import pretty_print + pretty_print(self) def plot(self, *args, **kwds): """ From 285b0fd03cb0d7b8a05c86527b2bf073cfaac416 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 23 Mar 2015 01:40:54 +0100 Subject: [PATCH 167/665] rename m as n in the StandardTableau promotion methods to match the notation of the Tableau promotion methods; minor optimization --- src/sage/combinat/tableau.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 9673c27d2bb..00d761ec877 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -2555,14 +2555,13 @@ def row_stabilizer(self): sage: rs.order() 1 """ - # Ensure that the permutations involve all elements of the # tableau, by including the identity permutation on the set [1..k]. k = self.size() - gens = [range(1,k+1)] - for i in range(len(self)): - for j in range(0, len(self[i])-1): - gens.append( (self[i][j], self[i][j+1]) ) + gens = [range(1, k+1)] + for row in self: + for j in range(0, len(row)-1): + gens.append( (row[j], row[j+1]) ) return PermutationGroup( gens ) @@ -2584,7 +2583,6 @@ def column_stabilizer(self): sage: PermutationGroupElement([(1,4)]) in cs True """ - return self.conjugate().row_stabilizer() def height(self): @@ -3954,7 +3952,7 @@ def standard_major_index(self): """ return sum(self.standard_descents()) - def promotion_inverse(self, m=None): + def promotion_inverse(self, n=None): """ Return the image of ``self`` under the inverse promotion operator. The optional variable `m` should be set to the size of ``self`` minus @@ -3994,11 +3992,11 @@ def promotion_inverse(self, m=None): sage: all( bk_promotion_inverse7(st) == st.promotion_inverse() for st in ST ) # long time True """ - if m is None: - m = self.size() - 1 - return StandardTableau(Tableau(self[:]).promotion_inverse(m)) + if n is None: + n = self.size() - 1 + return StandardTableau(Tableau(self[:]).promotion_inverse(n)) - def promotion(self, m=None): + def promotion(self, n=None): r""" Return the image of ``self`` under the promotion operator. @@ -4030,9 +4028,9 @@ def promotion(self, m=None): sage: parent(st.promotion()) Standard tableaux """ - if m is None: - m = self.size() - 1 - return StandardTableau(Tableau(self[:]).promotion(m)) + if n is None: + n = self.size() - 1 + return StandardTableau(Tableau(self[:]).promotion(n)) def from_chain(chain): """ From 9ee0d6e19ed03501a03333dfa4815f947735c0bc Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 24 Mar 2015 13:28:29 +0100 Subject: [PATCH 168/665] trac #18045: Wrong result returned by is_planar on a given embedding --- src/sage/graphs/generic_graph.py | 85 ++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 63158f74ff5..7fb0375dbb1 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3466,22 +3466,25 @@ def vertices_to_edges(x): ### Planarity def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False): - """ - Returns True if the graph is planar, and False otherwise. This - wraps the reference implementation provided by John Boyer of the + r""" + Test whether the graph is planar. + + This wraps the reference implementation provided by John Boyer of the linear time planarity algorithm by edge addition due to Boyer - Myrvold. (See reference code in graphs.planarity). + Myrvold. (See reference code in :mod:`sage.graphs.planarity`). - Note - the argument on_embedding takes precedence over - set_embedding. This means that only the on_embedding - combinatorial embedding will be tested for planarity and no - _embedding attribute will be set as a result of this function - call, unless on_embedding is None. + .. NOTE:: + + the argument on_embedding takes precedence over + ``set_embedding``. This means that only the ``on_embedding`` + combinatorial embedding will be tested for planarity and no + ``_embedding`` attribute will be set as a result of this function + call, unless ``on_embedding`` is None. REFERENCE: - - [1] John M. Boyer and Wendy J. Myrvold, On the Cutting Edge: - Simplified O(n) Planarity by Edge Addition. Journal of Graph + .. [1] John M. Boyer and Wendy J. Myrvold, On the Cutting Edge: + Simplified `O(n)` Planarity by Edge Addition. Journal of Graph Algorithms and Applications, Vol. 8, No. 3, pp. 241-273, 2004. @@ -3493,16 +3496,15 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se subgraph or minor as the second tuple entry. If the graph is planar, returns None as the second entry. - - ``on_embedding`` - the embedding dictionary to test - planarity on. (i.e.: will return True or False only for the given + - ``on_embedding`` - the embedding dictionary to test planarity + on. (i.e.: will return ``True`` or ``False`` only for the given embedding.) - - ``set_embedding`` - whether or not to set the - instance field variable that contains a combinatorial embedding - (clockwise ordering of neighbors at each vertex). This value will - only be set if a planar embedding is found. It is stored as a - Python dict: v1: [n1,n2,n3] where v1 is a vertex and n1,n2,n3 are - its neighbors. + - ``set_embedding`` - whether or not to set the instance field variable + that contains a combinatorial embedding (clockwise ordering of + neighbors at each vertex). This value will only be set if a planar + embedding is found. It is stored as a Python dict: ``v1: [n1,n2,n3]`` + where ``v1`` is a vertex and ``n1,n2,n3`` are its neighbors. - ``set_pos`` - whether or not to set the position dictionary (for plotting) to reflect the combinatorial embedding. @@ -3510,7 +3512,6 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se False. Also, the position dictionary will only be updated if a planar embedding is found. - EXAMPLES:: sage: g = graphs.CubeGraph(4) @@ -3587,13 +3588,21 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se sage: k.vertices() [0, 1, 2, 3, 4] + :trac:`18045`:: + + sage: g = graphs.CompleteGraph(4) + sage: g.is_planar(set_embedding=True) + True + sage: emb = {0 : [2,3,1], 1: [2,3,0], 2: [1,3,0], 3:[0,1,2]} + sage: g.is_planar(on_embedding=emb) + False """ if self.has_multiple_edges() or self.has_loops(): if set_embedding or (on_embedding is not None) or set_pos: raise NotImplementedError("Cannot compute with embeddings of multiple-edged or looped graphs.") else: return self.to_simple().is_planar(kuratowski=kuratowski) - if on_embedding: + if on_embedding is not None: if self._check_embedding_validity(on_embedding): return (0 == self.genus(minimal=False,set_embedding=False,on_embedding=on_embedding)) else: @@ -3994,7 +4003,7 @@ def is_drawn_free_of_edge_crossings(self): return True def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=False, circular=False, ordered=True): - """ + r""" Returns the minimal genus of the graph. The genus of a compact surface is the number of handles it @@ -4010,16 +4019,19 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal store an embedding attribute of the computed (minimal) genus of the graph. (Default is True). - - ``on_embedding (dict)`` - a combinatorial embedding - to compute the genus of the graph on. Note that this must be a - valid embedding for the graph. The dictionary structure is given - by: vertex1: [neighbor1, neighbor2, neighbor3], vertex2: [neighbor] - where there is a key for each vertex in the graph and a (clockwise) - ordered list of each vertex's neighbors as values. on_embedding - takes precedence over a stored _embedding attribute if minimal is - set to False. Note that as a shortcut, the user can enter - on_embedding=True to compute the genus on the current _embedding - attribute. (see eg's.) + - ``on_embedding`` (default: ``None``) - two kinds of input are allowed: + + - a dictionnary representing a combinatorial embedding on which the + genus should be computed. Note that this must be a valid embedding + for the graph. The dictionary structure is given by: ``vertex1: + [neighbor1, neighbor2, neighbor3], vertex2: [neighbor]`` where + there is a key for each vertex in the graph and a (clockwise) + ordered list of each vertex's neighbors as values. The value of + ``on_embedding`` takes precedence over a stored ``_embedding`` + attribute if minimal is set to ``False``. + + - The value ``True``, in order to indicate that the embedding stored + as ``_embedding`` should be used (see eg's). - ``minimal (boolean)`` - whether or not to compute the minimal genus of the graph (i.e., testing all embeddings). If @@ -4164,15 +4176,16 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal if on_embedding is not None: if self.has_loops() or self.is_directed() or self.has_multiple_edges(): raise NotImplementedError("Can't work with embeddings of non-simple graphs") - if on_embedding: #i.e., if on_embedding True (returns False if on_embedding is of type dict) + + if isinstance(on_embedding,dict): + faces = len(self.faces(on_embedding)) + return (2-verts+edges-faces) // 2 + elif on_embedding: try: faces = len(self.faces(self._embedding)) except AttributeError: raise AttributeError('graph must have attribute _embedding set to compute current (embedded) genus') return (2-verts+edges-faces) // 2 - else: # compute genus on the provided dict - faces = len(self.faces(on_embedding)) - return (2-verts+edges-faces) // 2 else: # then compute either maximal or minimal genus of all embeddings import genus From 478d5f9d534bfc74537ad1c838ce82f6e2059de1 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 24 Mar 2015 12:34:18 -0700 Subject: [PATCH 169/665] 16659: orthogonal_idempotents -> central_orthogonal_idempotents --- .../finite_dimensional_algebras_with_basis.py | 23 ++++++++++--------- src/sage/categories/semisimple_algebras.py | 12 +++++----- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fd057a385e7..14306b705cc 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -388,9 +388,10 @@ def principal_ideal(self, a, side='left'): return self.submodule([self.from_vector(v) for v in ideal.basis()], already_echelonized=True) - def orthogonal_idempotents(self): + def central_orthogonal_idempotents(self): r""" - Return a maximal family of orthogonal idempotents of ``self``. + Return a maximal family of central orthogonal idempotents of + ``self``. INPUT: @@ -402,13 +403,13 @@ def orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents() + sage: A.central_orthogonal_idempotents() [y, x] sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) - sage: A.orthogonal_idempotents() + sage: A.central_orthogonal_idempotents() [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], @@ -418,7 +419,7 @@ def orthogonal_idempotents(self): + 1/4*B[11]] """ Aquo = self.semisimple_quotient() - orth_quo = Aquo.orthogonal_idempotents() + orth_quo = Aquo.central_orthogonal_idempotents() return [self._lift_idempotent(x) for x in orth_quo] def _lift_idempotent(self, x): @@ -430,7 +431,7 @@ def _lift_idempotent(self, x): sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.orthogonal_idempotents() + sage: orth = Aquo.central_orthogonal_idempotents() sage: A._lift_idempotent(orth[1]) x """ @@ -474,7 +475,7 @@ def cartan_invariants_matrix(self, side='left'): [0 0 0 0 0 0 0 0 2] """ Aquo = self.semisimple_quotient() - orth_quo = Aquo.orthogonal_idempotents() + orth_quo = Aquo.central_orthogonal_idempotents() # Dimension of simple modules dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] @@ -503,7 +504,7 @@ def projective_indecomposables(self, side='left'): True """ - return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents()] + return [self.principal_ideal(e, side) for e in self.central_orthogonal_idempotents()] def pierce_decomposition_component(self, ei, ej): r""" @@ -522,7 +523,7 @@ def pierce_decomposition_component(self, ei, ej): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: idemp = A.orthogonal_idempotents() + sage: idemp = A.central_orthogonal_idempotents() sage: A.pierce_decomposition_component(idemp[1], idemp[0]) Free module generated by {0, 1} over Rational Field sage: A.pierce_decomposition_component(idemp[0], idemp[1]) @@ -533,7 +534,7 @@ def pierce_decomposition_component(self, ei, ej): of S4:: sage: A4 = SymmetricGroup(4).algebra(QQ) - sage: e = A4.orthogonal_idempotents()[2] + sage: e = A4.central_orthogonal_idempotents()[2] sage: A4.pierce_decomposition_component(e, e) Free module generated by {0, 1, 2, 3} over Rational Field """ @@ -564,7 +565,7 @@ def pierce_decomposition(self): """ import itertools decomp = [] - for (ei, ej) in itertools.product(self.orthogonal_idempotents(), + for (ei, ej) in itertools.product(self.central_orthogonal_idempotents(), repeat=2): decomp.append(self.pierce_decomposition_component(ei, ej)) return decomp diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 7ce1002e74e..af330187675 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -71,7 +71,7 @@ class WithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def orthogonal_idempotents(self): + def central_orthogonal_idempotents(self): r""" Return a maximal list of orthogonal idempotents of ``self``. @@ -83,7 +83,7 @@ def orthogonal_idempotents(self): EXAMPLES:: sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: A3.orthogonal_idempotents() + sage: A3.central_orthogonal_idempotents() [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), 1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + @@ -97,11 +97,11 @@ def orthogonal_idempotents(self): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() - sage: Aquo.orthogonal_idempotents() + sage: Aquo.central_orthogonal_idempotents() [B['y'], B['x']] """ return [x.lift() - for x in self.center().orthogonal_idempotents()] + for x in self.center().central_orthogonal_idempotents()] class Commutative(CategoryWithAxiom_over_base_ring): @@ -197,7 +197,7 @@ def rec(space, generators): return rec(self, generators) @cached_method - def orthogonal_idempotents(self): + def central_orthogonal_idempotents(self): r""" Return the minimum set of central orthogonal idempotents of ``self``. @@ -213,7 +213,7 @@ def orthogonal_idempotents(self): sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() - sage: orth = Z5.orthogonal_idempotents() + sage: orth = Z5.central_orthogonal_idempotents() sage: orth [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + From 15ec49468f36a82f14481e3f24d263a089ce761e Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 25 Mar 2015 22:43:15 -0700 Subject: [PATCH 170/665] typo --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 14306b705cc..bd8c4f38f5d 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -160,7 +160,6 @@ def radical_basis(self, cache_products=True): if p == 0: keys = list(self.basis().keys()) - # x[i,j] = product_on_basis(x,i).coefficient(j) cache = [{(i,j): c for i in keys for j,c in product_on_basis(y,i)} @@ -380,7 +379,7 @@ def principal_ideal(self, a, side='left'): elif side == 'right': phi = self.module_morphism(on_basis=lambda i: B[i]*a, codomain=self, - triangluar=True) + triangular=True) else: raise Exception("Side must be ``left`` or ``right``") ideal = phi.matrix().image() From d8b310ddfcda9bf6e3b4bfb076365f2b8fc26a53 Mon Sep 17 00:00:00 2001 From: Josh Swanson Date: Fri, 27 Mar 2015 01:21:30 -0700 Subject: [PATCH 171/665] Some minor tweaks, removed remaining old pickles --- src/sage/combinat/ribbon_shaped_tableau.py | 2 -- src/sage/combinat/ribbon_tableau.py | 2 -- src/sage/combinat/skew_partition.py | 9 ++++--- src/sage/combinat/skew_tableau.py | 10 ++++---- src/sage/combinat/tableau.py | 29 ++++++++++++---------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 3c4019b3eb5..04a1050e13c 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -120,8 +120,6 @@ def __setstate__(self, state): EXAMPLES:: - sage: loads( 'x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@\x14]\x8a\x0e\xdf\xb8\x968"\xceZ|\x00x\xef5\x11') # not tested -- broken - [[None, 1], [2, 3]] sage: loads(dumps( RibbonTableau([[None, 1],[2,3]]) )) [[None, 1], [2, 3]] """ diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index d0531108c63..c0eb84e427f 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -1037,11 +1037,14 @@ def to_dag(self, format="string"): EXAMPLES:: - sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag() + sage: dag = SkewPartition([[3, 3, 1], [1, 1]]).to_dag() sage: dag.edges() - [('0,1', '0,2', None), ('0,1', '1,1', None)] + [('0,1', '0,2', None), + ('0,1', '1,1', None), + ('0,2', '1,2', None), + ('1,1', '1,2', None)] sage: dag.vertices() - ['0,1', '0,2', '1,1', '2,0'] + ['0,1', '0,2', '1,1', '1,2', '2,0'] sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag(format="tuple") sage: dag.edges() [((0, 1), (0, 2), None), ((0, 1), (1, 1), None)] diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 1978b428bf3..b952fec2d6b 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -247,8 +247,9 @@ def _repr_list(self): """ return repr([list(row) for row in self]) - # Overwrite the object from CombinatorialObject - # until this is no longer around + # See #18024. CombinatorialObject provided __str__, though ClonableList + # doesn't. Emulate the old functionality. Possibly remove when + # CombinatorialObject is removed. __str__ = _repr_list def _repr_diagram(self): @@ -1418,8 +1419,7 @@ def _label_skew(list_of_cells, sk): """ i = 1 skew = [list(row) for row in sk] - for coords in list_of_cells: - (row, column) = coords + for row, column in list_of_cells: skew[row][column] = i i += 1 return skew @@ -2313,7 +2313,7 @@ def __iter__(self): """ from ribbon_tableau import RibbonTableaux_shape_weight_length for x in RibbonTableaux_shape_weight_length(self.p, self.mu, 1): - yield self.element_class(self, x[:]) + yield self.element_class(self, x) # October 2012: fixing outdated pickles which use the classes being deprecated from sage.structure.sage_object import register_unpickle_override diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 00d761ec877..686d982d59c 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -197,10 +197,10 @@ class Tableau(ClonableList): - A Tableau object constructed from ``t``. - A tableau in Sage is a finite list of lists (which can be entered as - arbitrary iterables), whose lengths are weakly decreasing. This list, - in particular, can be empty, representing the empty tableau. The - entries of a tableau can be any Sage objects. + A tableau is abstractly a mapping of cells in a partition to arbitrary + entries. It is often thought of as a finite list of lists (or generally + an iterable of iterables) of weakly decreasing lengths. This list, + in particular, can be empty, representing the empty tableau. Note that Sage uses the English convention for partitions and tableaux; the longer rows are displayed on top. @@ -300,7 +300,9 @@ def __init__(self, parent, t): sage: s is t # identical tableaux are distinct objects False - A tableau is immutable, see :trac:`15862`:: + A tableau is shallowly immutable. See :trac:`15862`. The entries + themselves may be mutable objects, though in that case the + resulting Tableau should be unhashable. sage: T = Tableau([[1,2],[2]]) sage: t0 = T[0] @@ -315,7 +317,7 @@ def __init__(self, parent, t): """ if isinstance(t, Tableau): # Since we are (supposed to be) immutable, we can share the underlying data - ClonableList.__init__(self, parent, list(t)) + ClonableList.__init__(self, parent, t) return # Normalize t to be a list of tuples. @@ -460,8 +462,9 @@ def _repr_list(self): """ return repr(map(list, self)) - # Overwrite the object from CombinatorialObject - # until this is no longer around + # See #18024. CombinatorialObject provided __str__, though ClonableList + # doesn't. Emulate the old functionality. Possibly remove when + # CombinatorialObject is removed. __str__ = _repr_list def _repr_diagram(self): @@ -4838,8 +4841,8 @@ def __contains__(self, t): if isinstance(t, SemistandardTableau): return self.max_entry is None or \ len(t) == 0 or \ - max(sum(t, ())) <= self.max_entry - elif t == []: + max(max(row) for row in t) <= self.max_entry + elif not t: return True elif Tableaux.__contains__(self, t): for row in t: @@ -5173,9 +5176,9 @@ def __contains__(self, x): if self.size==0: return x == [] - return SemistandardTableaux.__contains__(self, x) \ - and sum(map(len,x)) == self.size \ - and max(i for row in x for i in row) <= self.max_entry + return (SemistandardTableaux.__contains__(self, x) + and sum(map(len,x)) == self.size + and max(max(row) for row in x) <= self.max_entry) def cardinality(self): """ From c1c6a729de7fdbc8f77846afedfd5cf6c9f28005 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 27 Mar 2015 09:53:55 +0100 Subject: [PATCH 172/665] minor change, and fixing a broken iterator --- src/sage/combinat/skew_tableau.py | 30 +++++++++++++++++------------- src/sage/combinat/tableau.py | 7 ++++--- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index b952fec2d6b..7db54795d13 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1628,26 +1628,25 @@ def _repr_(self): def __iter__(self): """ - Iterate through ``self``. + Iterate through all standard skew tableaux having + no empty rows (before nonempty rows) and no empty columns + (before nonempty columns). EXAMPLES:: - sage: it = StandardTableaux().__iter__() + sage: it = StandardSkewTableaux().__iter__() sage: [next(it) for x in range(10)] [[], [[1]], - [[1, 2]], - [[1], [2]], - [[1, 2, 3]], - [[1, 3], [2]], - [[1, 2], [3]], - [[1], [2], [3]], - [[1, 2, 3, 4]], - [[1, 3, 4], [2]]] + [[1, 2]], [[1], [2]], [[None, 1], [2]], [[None, 2], [1]], + [[1, 2, 3]], [[1, 2], [3]], [[1, 3], [2]], + [[None, 1, 2], [3]]] """ n = 0 - for st in StandardSkewTableaux_size(n): - yield self.element_class(self, st) + while True: + for st in StandardSkewTableaux_size(n): + yield self.element_class(self, st) + n += 1 class StandardSkewTableaux_size(StandardSkewTableaux): """ @@ -1692,6 +1691,11 @@ def cardinality(self): def __iter__(self): """ + Iterate through all standard skew tableaux of size `n` having + no empty rows (before nonempty rows) and no empty columns + (before nonempty columns). (The last two requirements + ensure that the iterator terminates after finitely many steps.) + EXAMPLES:: sage: StandardSkewTableaux(2).list() @@ -1782,7 +1786,7 @@ def cardinality(self): def __iter__(self): """ - An iterator for all the standard skew tableau with shape of the + An iterator for all the standard skew tableaux with shape of the skew partition ``skp``. The standard skew tableaux are ordered lexicographically by the word obtained from their row reading. diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 686d982d59c..60e80672d0b 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -197,9 +197,10 @@ class Tableau(ClonableList): - A Tableau object constructed from ``t``. - A tableau is abstractly a mapping of cells in a partition to arbitrary - entries. It is often thought of as a finite list of lists (or generally - an iterable of iterables) of weakly decreasing lengths. This list, + A tableau is abstractly a mapping from the cells in a partition to + arbitrary objects (called entries). It is often represented as a + finite list of nonempty lists (or generally an iterable of + iterables) of weakly decreasing lengths. This list, in particular, can be empty, representing the empty tableau. Note that Sage uses the English convention for partitions and From f65bb00f9f3b5b37637ebb67e0cbefa56026078a Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Fri, 27 Mar 2015 14:36:11 +0100 Subject: [PATCH 173/665] Trac 18068: implement ModularForm_abstract.__ne__() --- src/sage/modular/modform/element.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 74c7dc044a0..0e1fb1292dd 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -235,6 +235,23 @@ def __eq__(self, other): else: return self.element() == other.element() + def __ne__(self, other): + """ + Return True if ``self != other``. + + EXAMPLES:: + + sage: f = Newforms(Gamma1(30), 2, names='a')[1] + sage: g = ModularForms(23, 2).0 + sage: f != g + True + sage: f != f + False + sage: f != loads(dumps(f)) + False + """ + return not (self == other) + def __cmp__(self, other): """ Compare self to other. If they are not the same object, but From af4ae72023545ce14eedf32fcdac0d969ef6dd9b Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Sat, 28 Mar 2015 21:08:44 +0100 Subject: [PATCH 174/665] Trac 18068: simplify comparison methods of modular forms --- src/sage/modular/local_comp/local_comp.py | 31 +++++-- src/sage/modular/modform/element.py | 100 +++------------------- 2 files changed, 36 insertions(+), 95 deletions(-) diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index df38b3c6eca..29ba601f4f3 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -275,7 +275,7 @@ def central_character(self): else: return SmoothCharacterGroupQp(self.prime(), self.coefficient_field()).character(chip.conductor().valuation(self.prime()), list((~chip).values_on_gens()) + [chi(a) * self.prime()**self.twist_factor()]) - def __cmp__(self, other): + def __eq__(self, other): r""" Comparison function. @@ -293,10 +293,31 @@ def __cmp__(self, other): sage: Pi == loads(dumps(Pi)) True """ - return (cmp(type(self), type(other)) - or cmp(self.prime(), other.prime()) - or cmp(self.newform(), other.newform()) - or cmp(self.twist_factor(), other.twist_factor())) + return (isinstance(other, LocalComponentBase) + and self.prime() == other.prime() + and self.newform() == other.newform() + and self.twist_factor() == other.twist_factor()) + + def __ne__(self, other): + """ + Return True if ``self != other``. + + EXAMPLE:: + + sage: Pi = LocalComponent(Newform("50a"), 5) + sage: Pi != LocalComponent(Newform("50a"), 3) + True + sage: Pi != LocalComponent(Newform("50b"), 5) + True + sage: Pi != QQ + True + sage: Pi != None + True + sage: Pi != loads(dumps(Pi)) + False + """ + return not (self == other) + class PrincipalSeries(LocalComponentBase): r""" diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 0e1fb1292dd..0cfba997f48 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -132,30 +132,6 @@ def _repr_(self): """ return str(self.q_expansion()) - def _ensure_is_compatible(self, other): - """ - Make sure self and other are compatible for arithmetic or - comparison operations. Raise an error if incompatible, - do nothing otherwise. - - EXAMPLES:: - - sage: f = ModularForms(DirichletGroup(17).0^2,2).2 - sage: g = ModularForms(DirichletGroup(17).0^2,2).1 - sage: h = ModularForms(17,4).0 - - sage: f._ensure_is_compatible(g) - - sage: f._ensure_is_compatible(h) - Traceback (most recent call last): - ... - ArithmeticError: Modular forms must be in the same ambient space. - """ - if not isinstance(other, ModularForm_abstract): - raise TypeError("Second argument must be a modular form.") - if self.parent().ambient() != other.parent().ambient(): - raise ArithmeticError("Modular forms must be in the same ambient space.") - def __call__(self, x, prec=None): """ Evaluate the q-expansion of this modular form at x. @@ -213,7 +189,6 @@ def qexp(self, prec=None): """ return self.q_expansion(prec) - def __eq__(self, other): """ Compare self to other. @@ -252,29 +227,6 @@ def __ne__(self, other): """ return not (self == other) - def __cmp__(self, other): - """ - Compare self to other. If they are not the same object, but - are of the same type, compare them as vectors. - - EXAMPLES:: - - sage: f = ModularForms(DirichletGroup(17).0^2,2).2 - sage: g = ModularForms(DirichletGroup(17).0^2,2).1 - sage: f == g ## indirect doctest - False - sage: f == f - True - """ - try: - self._ensure_is_compatible(other) - except Exception: - return self.parent().__cmp__(other.parent()) - if self.element() == other.element(): - return 0 - else: - return -1 - def _compute(self, X): """ Compute the coefficients of `q^n` of the power series of self, @@ -932,49 +884,17 @@ def __eq__(self, other): sage: f1.__eq__(f2) False """ - try: - self._ensure_is_compatible(other) - except Exception: + if (not isinstance(other, ModularForm_abstract) + or self.parent().ambient() != other.parent().ambient()): return False - if isinstance(other, Newform): - if self.q_expansion(self.parent().sturm_bound()) == other.q_expansion(other.parent().sturm_bound()): - return True - else: - return False - if is_ModularFormElement(other): - if self.element() == other.element(): - return True - else: - return False - - def __cmp__(self, other): - """ - Compare self with other. - - EXAMPLES:: - - sage: f1, f2 = Newforms(19,4,names='a') - sage: f1.__cmp__(f1) - 0 - sage: f1.__cmp__(f2) - -1 - sage: f2.__cmp__(f1) - -1 - """ - try: - self._ensure_is_compatible(other) - except Exception: - return self.parent().__cmp__(other.parent()) - if isinstance(other, Newform): - if self.q_expansion(self.parent().sturm_bound()) == other.q_expansion(other.parent().sturm_bound()): - return 0 - else: - return -1 - if is_ModularFormElement(other): - if self.element() == other.element(): - return 0 - else: - return -1 + if (isinstance(other, Newform) and + self.q_expansion(self.parent().sturm_bound()) + == other.q_expansion(other.parent().sturm_bound())): + return True + if (is_ModularFormElement(other) and + self.element() == other.element()): + return True + return False def abelian_variety(self): """ From bf5bec39f41ff6898b32bffafd070853f9b7ada7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Mon, 30 Mar 2015 14:06:35 +0300 Subject: [PATCH 175/665] Corrected trailing spaces and some conventions --- src/sage/geometry/polyhedron/plot.py | 89 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index e71d2e16101..048196d5bd5 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -238,14 +238,15 @@ def cyclic_sort_vertices_2d(Vlist): A line in the direction (1, 0), A ray in the direction (0, 1)] """ - if len(Vlist)==0: return Vlist + if len(Vlist) == 0: + return Vlist Vlist = list(Vlist) result = [] adjacency_matrix = Vlist[0].polyhedron().vertex_adjacency_matrix() # Any object in Vlist has 0,1, or 2 adjacencies. Break into connected chains: chain = [ Vlist.pop() ] - while len(Vlist)>0: + while len(Vlist) > 0: first_index = chain[0].index() last_index = chain[-1].index() for v in Vlist: @@ -253,11 +254,11 @@ def cyclic_sort_vertices_2d(Vlist): if adjacency_matrix[last_index, v_index] == 1: chain = chain + [v] Vlist.remove(v) - break; + break if adjacency_matrix[first_index, v.index()] == 1: chain = [v] + chain Vlist.remove(v) - break; + break else: result += chain chain = [ Vlist.pop() ] @@ -317,17 +318,17 @@ def __init__(self, projection_point): self.projection_point = vector(projection_point) self.dim = self.projection_point.degree() - pproj = vector(RDF,self.projection_point) + pproj = vector(RDF, self.projection_point) self.psize = norm(pproj) if (self.psize).is_zero(): raise ValueError("projection direction must be a non-zero vector.") v = vector(RDF, [0.0]*(self.dim-1) + [self.psize]) - pproj - polediff = matrix(RDF,v).transpose() + polediff = matrix(RDF, v).transpose() denom = RDF((polediff.transpose()*polediff)[0][0]) if denom.is_zero(): - self.house = identity_matrix(RDF,self.dim) + self.house = identity_matrix(RDF, self.dim) else: - self.house = identity_matrix(RDF,self.dim) \ + self.house = identity_matrix(RDF, self.dim) \ - 2*polediff*polediff.transpose()/denom # Householder reflector def __call__(self, x): @@ -401,13 +402,13 @@ def __init__(self, projection_direction, height=1.1, center=0): spcenter = height * self.projection_dir/norm(self.projection_dir) self.height = height v = vector(RDF, [0.0]*(self.dim-1) + [self.height]) - spcenter - polediff = matrix(RDF,v).transpose() + polediff = matrix(RDF, v).transpose() denom = (polediff.transpose()*polediff)[0][0] if denom.is_zero(): - self.house = identity_matrix(RDF,self.dim) + self.house = identity_matrix(RDF, self.dim) else: - self.house = identity_matrix(RDF,self.dim) \ - - 2*polediff*polediff.transpose()/denom #Householder reflector + self.house = identity_matrix(RDF, self.dim) \ + - 2*polediff*polediff.transpose()/denom # Householder reflector def __call__(self, x): """ @@ -422,7 +423,7 @@ def __call__(self, x): sage: proj.__call__([1,2,3]) (0.56162854..., 2.09602626...) """ - v = vector(RDF,x) - self.center + v = vector(RDF, x) - self.center if v.is_zero(): raise ValueError("The origin must not be a vertex.") v = v/norm(v) # normalize vertices to unit sphere @@ -679,8 +680,8 @@ def coordinates_of(self, coord_index_list): def _init_dimension(self): """ - Internal function: Initialize from polyhedron with - projected coordinates. Must always be called after + Internal function: Initialize from polyhedron with + projected coordinates. Must always be called after a coordinate projection. TESTS:: @@ -728,8 +729,8 @@ def show(self, *args, **kwds): def _init_from_2d(self, polyhedron): """ - Internal function: Initialize from polyhedron in - 2-dimensional space. The polyhedron could be lower + Internal function: Initialize from polyhedron in + 2-dimensional space. The polyhedron could be lower dimensional. TESTS:: @@ -750,8 +751,8 @@ def _init_from_2d(self, polyhedron): def _init_from_3d(self, polyhedron): """ - Internal function: Initialize from polyhedron in - 3-dimensional space. The polyhedron could be + Internal function: Initialize from polyhedron in + 3-dimensional space. The polyhedron could be lower dimensional. TESTS:: @@ -812,7 +813,7 @@ def _init_lines_arrows(self, polyhedron): if not obj[i].is_vertex(): continue for j in range(len(obj)): if polyhedron.vertex_adjacency_matrix()[i,j] == 0: continue - if i no polygon + if polyhedron.dim() <= 1: # empty or 0d or 1d polyhedron => no polygon return None def defining_equation(): # corresponding to a polygon @@ -936,23 +937,23 @@ def adjacent_vertices(i): self.face_inequalities = face_inequalities if polyhedron.n_lines() == 0: - assert len(faces)>0, "no vertices?" + assert len(faces) > 0, "no vertices?" self.polygons.extend( [self.coord_indices_of(f) for f in faces] ) return # now some special cases if there are lines (dim < ambient_dim) polygons = [] - if polyhedron.n_lines()==1: - assert len(faces)>0, "no vertices?" + if polyhedron.n_lines() == 1: + assert len(faces) > 0, "no vertices?" aline = next(polyhedron.line_generator()) for shift in [aline(), -aline()]: for coords in faces: - assert len(coords)==2, "There must be two points." + assert len(coords) == 2, "There must be two points." polygons.append( [ coords[0],coords[1], coords[1]+shift, coords[0]+shift ] ) - if polyhedron.n_lines()==2: + if polyhedron.n_lines() == 2: [line1, line2] = [l for l in polyhedron.line_generator()] l1 = line1() l2 = line2() @@ -1093,7 +1094,7 @@ def render_wireframe_3d(self, **kwds): sage: print wire.tachyon().split('\n')[77] # for testing FCylinder base -1.0 1.0 -1.0 apex -1.0 -1.0 -1.0 rad 0.005 texture... """ - wireframe = []; + wireframe = [] for l in self.lines: l_coords = self.coordinates_of(l) wireframe.append( line3d(l_coords, **kwds)) @@ -1205,28 +1206,28 @@ def render_2d(self, point_opts={}, line_opts={}, polygon_opts={}): polygon_opts.setdefault('zorder', 0) plt += self.render_fill_2d(**polygon_opts) return plt - + def render_3d(self, point_opts={}, line_opts={}, polygon_opts={}): """ Return 3d rendering of a polyhedron projected into 3-dimensional ambient space. - + EXAMPLES:: - + sage: p1 = Polyhedron(vertices=[[1,1,1]], rays=[[1,1,1]]) sage: p2 = Polyhedron(vertices=[[2,0,0], [0,2,0], [0,0,2]]) sage: p3 = Polyhedron(vertices=[[1,0,0], [0,1,0], [0,0,1]], rays=[[-1,-1,-1]]) sage: p1.projection().plot() + p2.projection().plot() + p3.projection().plot() Graphics3d Object - + It correctly handles various degenerate cases:: - + sage: Polyhedron(lines=[[1,0,0],[0,1,0],[0,0,1]]).plot() # whole space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], + sage: Polyhedron(vertices=[[1,1,1]], rays=[[1,0,0]], ....: lines=[[0,1,0],[0,0,1]]).plot() # half space Graphics3d Object - sage: Polyhedron(vertices=[[1,1,1]], + sage: Polyhedron(vertices=[[1,1,1]], ....: lines=[[0,1,0],[0,0,1]]).plot() # R^2 in R^3 Graphics3d Object sage: Polyhedron(rays=[[0,1,0],[0,0,1]], lines=[[1,0,0]]).plot() # quadrant wedge in R^2 @@ -1251,8 +1252,8 @@ def render_3d(self, point_opts={}, line_opts={}, polygon_opts={}): if isinstance(polygon_opts, dict): plt += self.render_solid_3d(**polygon_opts) return plt - - def tikz(self, view=[0,0,1], angle=0, scale=2, + + def tikz(self, view=[0, 0, 1], angle=0, scale=2, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False): r""" @@ -1361,19 +1362,19 @@ def tikz(self, view=[0,0,1], angle=0, scale=2, raise NotImplementedError("The polytope has to live in 2 or 3 dimensions.") elif self.polyhedron_dim < 2 or self.polyhedron_dim > 3: raise NotImplementedError("The polytope has to be 2 or 3-dimensional.") - elif self.polyhedron_ambient_dim == 2: #self is a polygon in 2-space + elif self.polyhedron_ambient_dim == 2: # self is a polygon in 2-space return self._tikz_2d(scale, edge_color, facet_color, opacity, vertex_color, axis) - elif self.polyhedron_dim == 2: # self is a polygon in 3-space + elif self.polyhedron_dim == 2: # self is a polygon in 3-space return self._tikz_2d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) - else: #self is a 3-polytope in 3-space + else: # self is a 3-polytope in 3-space return self._tikz_3d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" - Return a string ``tikz_pic`` consisting of a tikz picture of + Return a string ``tikz_pic`` consisting of a tikz picture of ``self``, which is assumed to be a polygon on the plane. INPUT: @@ -1489,7 +1490,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, r""" Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` according to a projection ``view`` and an angle ``angle`` - obtained via Jmol through the current state property. ``self`` is + obtained via Jmol through the current state property. ``self`` is assumed to be a polygon in 3-space. INPUT: @@ -1538,7 +1539,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, The ``facet_color`` is the filing color of the polytope (polygon). """ view_vector = vector(RDF, view) - rot = rotate_arbitrary(view_vector,-(angle/360)*2*pi) + rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi) rotation_matrix = rot[:2].transpose() # Creates the nodes, coordinate and tag for every vertex of the polytope. @@ -1617,7 +1618,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, r""" Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` according to a projection ``view`` and an angle ``angle`` - obtained via Jmol through the current state property. ``self`` is + obtained via Jmol through the current state property. ``self`` is assumed to be a 3-polytope in 3-space. INPUT: From 4d7f14d24e1218e471aef1c2c5369d1dfe72b807 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 31 Mar 2015 16:53:33 +0200 Subject: [PATCH 176/665] New method: _init_linear_code --- src/sage/coding/linear_code.py | 58 +++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 8c2af5f3472..698cb7a19ac 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -762,6 +762,58 @@ class LinearCode(module.Module): # 3 # sage: C.minimum_distance_why() # optional (net connection) # Ub(7,4) = 3 follows by the Griesmer bound. + + def _init_linear_code(self, base_field, length): + """ + Initialize mandatory parameters for a Linear Code object. + + This is a private method, which should be called by the constructor of + every linear code as it automatically initializes the some + mandatory parameters of a Linear Code object, and sets this object as + a valid member of the Sage category framework. + + INPUT: + + - ``base_field`` -- the base field of ``self`` + + - ``length`` -- the length of ``self`` + + EXAMPLES: + + We first create a new LinearCode subclass + :: + + sage: class CodeExample(LinearCode): + ....: def __init__(self, field, length, dimension): + ....: self._init_linear_code(field, length) + ....: self._dimension = dimension + + We now create a member of our newly made class + :: + + sage: C = CodeExample(GF(17), 10, 5) + + We can check its existence and parameters + :: + + sage: C + Linear code of length 10, dimension 5 over Finite Field of size 17 + + And we can check that it is truly a part of the framework category + :: + + sage: C.parent() + + sage: C.category() + Category of facade finite dimensional vector spaces with basis over Finite Field of size 17 + """ + self._base_field = base_field + self._length = length + cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() + facade_for = VectorSpace(self._base_field, self._length) + self.Element = type(facade_for.an_element()) # for when we make this a non-facade parent + Parent.__init__(self, base=base_field, facade=facade_for, category=cat) + def __init__(self, generator_matrix, d=None): r""" See the docstring for :meth:`LinearCode`. @@ -823,13 +875,9 @@ def __init__(self, generator_matrix, d=None): if generator_matrix.nrows() == 0: raise ValueError("this linear code contains no non-zero vector") - cat = Modules(base_ring).FiniteDimensional().WithBasis().Finite() - facade_for = generator_matrix.row(0).parent() - self.Element = type(generator_matrix.row(0)) # for when we make this a non-facade parent - Parent.__init__(self, base=base_ring, facade=facade_for, category=cat) + self._init_linear_code(base_ring, generator_matrix.ncols()) self._gens = generator_matrix.rows() self._generator_matrix = generator_matrix - self._length = generator_matrix.ncols() self._dimension = generator_matrix.rank() self._minimum_distance = d From bf70359e1dd818e8dfc066ad2efa4ea03e06144d Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 31 Mar 2015 17:02:29 +0200 Subject: [PATCH 177/665] New method: base_field --- src/sage/coding/linear_code.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 698cb7a19ac..453f09bce60 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1108,6 +1108,19 @@ def assmus_mattson_designs(self, t, mode=None): return ans return 0 + def base_field(self): + r""" + Return the base field of ``self``. + + EXAMPLES:: + + sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: C = LinearCode(G) + sage: C.base_field() + Finite Field of size 2 + """ + return self._base_field + def basis(self): r""" Returns a basis of `self`. From a425a89873d194bfdff1add267502a8f84ca6e08 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 3 Apr 2015 14:50:38 +0200 Subject: [PATCH 178/665] Changed structure of file: now contains an abstract class AbstractLinearCode for linear codes --- src/sage/coding/linear_code.py | 409 +++++++++++++++++---------------- 1 file changed, 211 insertions(+), 198 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 453f09bce60..85876347a58 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -693,84 +693,18 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, for N in self_orthogonal_binary_codes(n, k, d, child, BC, in_test=in_test): if out_test(N): yield N -############################ linear codes python class ######################## - -class LinearCode(module.Module): - r""" - Linear codes over a finite field or finite ring. - - A *linear code* is a subspace of a vector space over a finite field. It can - be defined by one of its basis or equivalently a generator matrix (a `k - \times n` matrix of full rank `k`). - - See :wikipedia:`Linear_code` for more information. - - INPUT: - - - ``generator_matrix`` -- a generator matrix over a finite field (``G`` can be - defined over a finite ring but the matrices over that ring must have - certain attributes, such as ``rank``) - - - ``d`` -- (optional, default: ``None``) the minimum distance of the code - - .. NOTE:: - - The veracity of the minimum distance ``d``, if provided, is not - checked. - - - EXAMPLES:: - - sage: MS = MatrixSpace(GF(2),4,7) - sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) - sage: C = LinearCode(G) - sage: C - Linear code of length 7, dimension 4 over Finite Field of size 2 - sage: C.base_ring() - Finite Field of size 2 - sage: C.dimension() - 4 - sage: C.length() - 7 - sage: C.minimum_distance() - 3 - sage: C.spectrum() - [1, 0, 0, 7, 7, 0, 0, 1] - sage: C.weight_distribution() - [1, 0, 0, 7, 7, 0, 0, 1] - - The minimum distance of the code, if known, can be provided as an - optional parameter.:: - - sage: C = LinearCode(G, d=3) - sage: C.minimum_distance() - 3 - - Another example.:: - - sage: MS = MatrixSpace(GF(5),4,7) - sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) - sage: C = LinearCode(G) - sage: C - Linear code of length 7, dimension 4 over Finite Field of size 5 - - AUTHORS: - - - David Joyner (11-2005) +class AbstractLinearCode(module.Module): """ - # sage: C.minimum_distance_upper_bound() # optional (net connection) - # 3 - # sage: C.minimum_distance_why() # optional (net connection) - # Ub(7,4) = 3 follows by the Griesmer bound. - - def _init_linear_code(self, base_field, length): + Abstract class for linear codes. + + This class contains all methods that can be used on Linear Codes + and on Linear Codes families. + So, every Linear Code-related class should inherit from this abstract + method. + """ + def __init__(self, base_field, length): """ - Initialize mandatory parameters for a Linear Code object. - - This is a private method, which should be called by the constructor of - every linear code as it automatically initializes the some - mandatory parameters of a Linear Code object, and sets this object as - a valid member of the Sage category framework. + Initializes mandatory parameters for a Linear Code object. INPUT: @@ -780,32 +714,41 @@ def _init_linear_code(self, base_field, length): EXAMPLES: - We first create a new LinearCode subclass - :: + We first create a new LinearCode subclass:: - sage: class CodeExample(LinearCode): + sage: class CodeExample(sage.coding.linear_code.AbstractLinearCode): ....: def __init__(self, field, length, dimension): - ....: self._init_linear_code(field, length) + ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length) ....: self._dimension = dimension + ....: def generator_matrix(self): + ....: return matrix(self.base_field(), self.dimension(), self.length(), {(i,i):1 for i in range(self.dimension())}) + ....: def _repr_(self): + ....: return "Dummy code of length %d, dimension %d over %s" % (self.length(), self.dimension(), self.base_field()) - We now create a member of our newly made class - :: + We now create a member of our newly made class:: sage: C = CodeExample(GF(17), 10, 5) - We can check its existence and parameters - :: + We can check its existence and parameters:: sage: C - Linear code of length 10, dimension 5 over Finite Field of size 17 + Dummy code of length 10, dimension 5 over Finite Field of size 17 - And we can check that it is truly a part of the framework category - :: + We can check that it is truly a part of the framework category:: sage: C.parent() sage: C.category() Category of facade finite dimensional vector spaces with basis over Finite Field of size 17 + + And any method that works on linear codes works for our new dummy code:: + + sage: C.minimum_distance() + 1 + sage: C.is_self_orthogonal() + False + sage: print C.is_permutation_equivalent(C.dual_code()) #long time + True """ self._base_field = base_field self._length = length @@ -814,87 +757,6 @@ def _init_linear_code(self, base_field, length): self.Element = type(facade_for.an_element()) # for when we make this a non-facade parent Parent.__init__(self, base=base_field, facade=facade_for, category=cat) - def __init__(self, generator_matrix, d=None): - r""" - See the docstring for :meth:`LinearCode`. - - EXAMPLES:: - - sage: MS = MatrixSpace(GF(2),4,7) - sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) - sage: C = LinearCode(G) # indirect doctest - sage: C - Linear code of length 7, dimension 4 over Finite Field of size 2 - - The minimum distance of the code, if known, can be provided as an - optional parameter.:: - - sage: C = LinearCode(G, d=3) - sage: C.minimum_distance() - 3 - - TESTS:: - - sage: C = codes.HammingCode(3, GF(2)) - sage: TestSuite(C).run() - - Check that it works even with input matrix with non full rank (see - :trac:`17452`):: - - sage: K. = GF(4) - sage: G = matrix([[a, a + 1, 1, a + 1, 1, 0, 0], - ....: [0, a, a + 1, 1, a + 1, 1, 0], - ....: [0, 0, a, a + 1, 1, a + 1, 1], - ....: [a + 1, 0, 1, 0, a + 1, 1, a + 1], - ....: [a, a + 1, a + 1, 0, 0, a + 1, 1], - ....: [a + 1, a, a, 1, 0, 0, a + 1], - ....: [a, a + 1, 1, a + 1, 1, 0, 0]]) - sage: C = LinearCode(G) - sage: C.basis() - [(1, 0, 0, a + 1, 0, 1, 0), - (0, 1, 0, 0, a + 1, 0, 1), - (0, 0, 1, a, a + 1, a, a + 1)] - sage: C.minimum_distance() - 3 - - Forbid the zero vector space (see :trac:`17452` and :trac:`6486`):: - - sage: G = matrix(GF(2), [[0,0,0]]) - sage: C = LinearCode(G) - Traceback (most recent call last): - ... - ValueError: this linear code contains no non-zero vector - """ - base_ring = generator_matrix.base_ring() - # if the matrix does not have full rank we replace it - if generator_matrix.rank() != generator_matrix.nrows(): - from sage.matrix.constructor import matrix - basis = generator_matrix.row_space().basis() - generator_matrix = matrix(base_ring, basis) - - if generator_matrix.nrows() == 0: - raise ValueError("this linear code contains no non-zero vector") - - self._init_linear_code(base_ring, generator_matrix.ncols()) - self._gens = generator_matrix.rows() - self._generator_matrix = generator_matrix - self._dimension = generator_matrix.rank() - self._minimum_distance = d - - def _repr_(self): - r""" - See the docstring for :meth:`LinearCode`. - - EXAMPLES:: - - sage: MS = MatrixSpace(GF(2),4,7) - sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) - sage: C = LinearCode(G) - sage: C # indirect doctest - Linear code of length 7, dimension 4 over Finite Field of size 2 - """ - return "Linear code of length %s, dimension %s over %s"%(self.length(), self.dimension(), self.base_ring()) - def _an_element_(self): r""" Return an element of the linear code. Currently, it simply returns @@ -954,31 +816,6 @@ def automorphism_group_gens(self, equivalence="semilinear"): return aut_group_can_label.get_autom_gens(), \ aut_group_can_label.get_autom_order() - def __iter__(self): - """ - Return an iterator over the elements of this linear code. - - EXAMPLES:: - - sage: C = codes.HammingCode(3,GF(2)) - sage: [list(c) for c in C if c.hamming_weight() < 4] - [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 1], - [0, 1, 0, 0, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0], - [1, 1, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0, 0], - [0, 1, 0, 1, 0, 1, 0], [0, 0, 1, 1, 0, 0, 1]] - - TESTS:: - - sage: C = codes.HammingCode(3,GF(2)) - sage: L = list(C) - sage: L[10].is_immutable() - True - - """ - from sage.modules.finite_submodule_iter import \ - FiniteFieldsubspace_iterator - return FiniteFieldsubspace_iterator(self.generator_matrix(), immutable=True) - def ambient_space(self): r""" Returns the ambient vector space of `self`. @@ -1952,7 +1789,10 @@ def gens(self): sage: C.gens() [(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)] """ - return self._gens + if hasattr(self, "_gens"): + return self._gens + else: + return self.generator_matrix().rows() def genus(self): r""" @@ -1978,6 +1818,32 @@ def genus(self): gammaC = n+1-k-d return gammaC + def __iter__(self): + """ + Return an iterator over the elements of this linear code. + + EXAMPLES:: + + sage: C = codes.HammingCode(3,GF(2)) + sage: [list(c) for c in C if c.hamming_weight() < 4] + [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 1], + [0, 1, 0, 0, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0], + [1, 1, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0, 0], + [0, 1, 0, 1, 0, 1, 0], [0, 0, 1, 1, 0, 0, 1]] + + TESTS:: + + sage: C = codes.HammingCode(3,GF(2)) + sage: L = list(C) + sage: L[10].is_immutable() + True + + """ + from sage.modules.finite_submodule_iter import \ + FiniteFieldsubspace_iterator + return FiniteFieldsubspace_iterator(self.generator_matrix(), immutable=True) + + def information_set(self): """ Return an information set of the code. @@ -2298,8 +2164,6 @@ def minimum_distance(self, algorithm=None): # If the minimum distance has already been computed or provided by # the user then simply return the stored value. # This is done only if algorithm is None. - if self._minimum_distance is not None and algorithm is None: - return self._minimum_distance if algorithm not in (None, "gap", "guava"): raise ValueError("The algorithm argument must be one of None, " "'gap' or 'guava'; got '{0}'".format(algorithm)) @@ -2320,8 +2184,7 @@ def minimum_distance(self, algorithm=None): #print "Running Guava's MinimumWeight ...\n" return ZZ(d) Gstr = "%s*Z(%s)^0"%(gapG, q) - self._minimum_distance = min_wt_vec_gap(Gstr,n,k,F).hamming_weight() - return self._minimum_distance + return min_wt_vec_gap(Gstr,n,k,F).hamming_weight() def module_composition_factors(self, gp): r""" @@ -3255,3 +3118,153 @@ def LinearCodeFromVectorSpace(V, d=None): G = MS([B[i].list() for i in range(k)]) return LinearCode(G, d=d) +############################ linear codes python class ######################## + +class LinearCode(AbstractLinearCode): + r""" + Linear codes over a finite field or finite ring. + + A *linear code* is a subspace of a vector space over a finite field. It can + be defined by one of its basis or equivalently a generator matrix (a `k + \times n` matrix of full rank `k`). + + See :wikipedia:`Linear_code` for more information. + + INPUT: + + - ``generator_matrix`` -- a generator matrix over a finite field (``G`` can be + defined over a finite ring but the matrices over that ring must have + certain attributes, such as ``rank``) + + - ``d`` -- (optional, default: ``None``) the minimum distance of the code + + .. NOTE:: + + The veracity of the minimum distance ``d``, if provided, is not + checked. + + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(2),4,7) + sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: C = LinearCode(G) + sage: C + Linear code of length 7, dimension 4 over Finite Field of size 2 + sage: C.base_ring() + Finite Field of size 2 + sage: C.dimension() + 4 + sage: C.length() + 7 + sage: C.minimum_distance() + 3 + sage: C.spectrum() + [1, 0, 0, 7, 7, 0, 0, 1] + sage: C.weight_distribution() + [1, 0, 0, 7, 7, 0, 0, 1] + + The minimum distance of the code, if known, can be provided as an + optional parameter.:: + + sage: C = LinearCode(G, d=3) + sage: C.minimum_distance() + 3 + + Another example.:: + + sage: MS = MatrixSpace(GF(5),4,7) + sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: C = LinearCode(G) + sage: C + Linear code of length 7, dimension 4 over Finite Field of size 5 + + AUTHORS: + + - David Joyner (11-2005) + """ + # sage: C.minimum_distance_upper_bound() # optional (net connection) + # 3 + # sage: C.minimum_distance_why() # optional (net connection) + # Ub(7,4) = 3 follows by the Griesmer bound. + + def __init__(self, generator_matrix, d=None): + r""" + See the docstring for :meth:`LinearCode`. + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(2),4,7) + sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: C = LinearCode(G) # indirect doctest + sage: C + Linear code of length 7, dimension 4 over Finite Field of size 2 + + The minimum distance of the code, if known, can be provided as an + optional parameter.:: + + sage: C = LinearCode(G, d=3) + sage: C.minimum_distance() + 3 + + TESTS:: + + sage: C = codes.HammingCode(3, GF(2)) + sage: TestSuite(C).run() + + Check that it works even with input matrix with non full rank (see + :trac:`17452`):: + + sage: K. = GF(4) + sage: G = matrix([[a, a + 1, 1, a + 1, 1, 0, 0], + ....: [0, a, a + 1, 1, a + 1, 1, 0], + ....: [0, 0, a, a + 1, 1, a + 1, 1], + ....: [a + 1, 0, 1, 0, a + 1, 1, a + 1], + ....: [a, a + 1, a + 1, 0, 0, a + 1, 1], + ....: [a + 1, a, a, 1, 0, 0, a + 1], + ....: [a, a + 1, 1, a + 1, 1, 0, 0]]) + sage: C = LinearCode(G) + sage: C.basis() + [(1, 0, 0, a + 1, 0, 1, 0), + (0, 1, 0, 0, a + 1, 0, 1), + (0, 0, 1, a, a + 1, a, a + 1)] + sage: C.minimum_distance() + 3 + + Forbid the zero vector space (see :trac:`17452` and :trac:`6486`):: + + sage: G = matrix(GF(2), [[0,0,0]]) + sage: C = LinearCode(G) + Traceback (most recent call last): + ... + ValueError: this linear code contains no non-zero vector + """ + base_ring = generator_matrix.base_ring() + # if the matrix does not have full rank we replace it + if generator_matrix.rank() != generator_matrix.nrows(): + from sage.matrix.constructor import matrix + basis = generator_matrix.row_space().basis() + generator_matrix = matrix(base_ring, basis) + + if generator_matrix.nrows() == 0: + raise ValueError("this linear code contains no non-zero vector") + + super(LinearCode, self).__init__(base_ring, generator_matrix.ncols()) + self._gens = generator_matrix.rows() + self._generator_matrix = generator_matrix + self._dimension = generator_matrix.rank() + self._minimum_distance = d + + def _repr_(self): + r""" + See the docstring for :meth:`LinearCode`. + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(2),4,7) + sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) + sage: C = LinearCode(G) + sage: C # indirect doctest + Linear code of length 7, dimension 4 over Finite Field of size 2 + """ + return "Linear code of length %s, dimension %s over %s"%(self.length(), self.dimension(), self.base_ring()) From 67e950df6d8ad3d35d3bac1113cba4091ef3fbf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 2 Apr 2015 18:09:44 +0200 Subject: [PATCH 179/665] replacing TransitiveIdeal by RecursivelyEnumeratedSet in sage library --- src/sage/categories/crystals.py | 45 +++++------ src/sage/categories/finite_semigroups.py | 11 ++- .../categories/highest_weight_crystals.py | 8 +- src/sage/combinat/crystals/alcove_path.py | 8 +- src/sage/combinat/enumerated_sets.py | 5 +- .../rigged_configurations/kr_tableaux.py | 7 +- .../rigged_configurations.py | 7 +- .../tensor_product_kr_tableaux.py | 7 +- .../combinat/root_system/pieri_factors.py | 10 ++- .../root_system/root_lattice_realizations.py | 28 ++++--- src/sage/groups/conjugacy_classes.py | 78 ++++++++++++++++--- 11 files changed, 137 insertions(+), 77 deletions(-) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 8786ac5cb5d..4b4d7eb5eeb 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -223,16 +223,12 @@ def __iter__(self, index_set=None, max_depth=float('inf')): sage: C.__iter__.__module__ 'sage.categories.crystals' sage: g = C.__iter__() - sage: next(g) + sage: for _ in range(5): next(g) (-Lambda[0] + Lambda[2],) - sage: next(g) (Lambda[0] - Lambda[1] + delta,) - sage: next(g) - (Lambda[1] - Lambda[2] + delta,) - sage: next(g) - (-Lambda[0] + Lambda[2] + delta,) - sage: next(g) (Lambda[1] - Lambda[2],) + (Lambda[0] - Lambda[1],) + (Lambda[1] - Lambda[2] + delta,) sage: sorted(C.__iter__(index_set=[1,2]), key=str) [(-Lambda[0] + Lambda[2],), @@ -245,17 +241,12 @@ def __iter__(self, index_set=None, max_depth=float('inf')): (Lambda[1] - Lambda[2],)] """ + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet if index_set is None: index_set = self.index_set() - if max_depth < float('inf'): - from sage.combinat.backtrack import TransitiveIdealGraded - return TransitiveIdealGraded(lambda x: [x.f(i) for i in index_set] - + [x.e(i) for i in index_set], - self.module_generators, max_depth).__iter__() - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(lambda x: [x.f(i) for i in index_set] - + [x.e(i) for i in index_set], - self.module_generators).__iter__() + succ = lambda x: [x.f(i) for i in index_set] + [x.e(i) for i in index_set] + R = RecursivelyEnumeratedSet(self.module_generators, succ, structure=None) + return R.breadth_first_search_iterator(max_depth) def subcrystal(self, index_set=None, generators=None, max_depth=float("inf"), direction="both"): @@ -302,19 +293,19 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float("inf"), index_set = self.index_set() if generators is None: generators = self.module_generators - from sage.combinat.backtrack import TransitiveIdealGraded + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet if direction == 'both': - return TransitiveIdealGraded(lambda x: [x.f(i) for i in index_set] - + [x.e(i) for i in index_set], - generators, max_depth) - if direction == 'upper': - return TransitiveIdealGraded(lambda x: [x.e(i) for i in index_set], - generators, max_depth) - if direction == 'lower': - return TransitiveIdealGraded(lambda x: [x.f(i) for i in index_set], - generators, max_depth) - raise ValueError("direction must be either 'both', 'upper', or 'lower'") + succ = lambda x: [x.f(i) for i in index_set] + [x.e(i) for i in index_set] + elif direction == 'upper': + succ = lambda x: [x.e(i) for i in index_set] + elif direction == 'lower': + succ = lambda x: [x.f(i) for i in index_set] + else: + raise ValueError("direction must be either 'both', 'upper', or 'lower'") + return RecursivelyEnumeratedSet(generators, succ, + structure=None, enumeration='breadth', + max_depth=max_depth) def crystal_morphism(self, g, index_set = None, automorphism = lambda i : i, direction = 'down', direction_image = 'down', similarity_factor = None, similarity_factor_domain = None, cached = False, acyclic = True): diff --git a/src/sage/categories/finite_semigroups.py b/src/sage/categories/finite_semigroups.py index 5c84f41e34e..341ebbbbc7e 100644 --- a/src/sage/categories/finite_semigroups.py +++ b/src/sage/categories/finite_semigroups.py @@ -143,8 +143,10 @@ def __iter__(self): ['y', 'x', 'xy', 'yx'] """ - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(self.succ_generators(side = "right"), self.semigroup_generators()).__iter__() + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(self.semigroup_generators(), + self.succ_generators(side = "right"), + structure=None).naive_search_iterator() def ideal(self, gens, side="twosided"): r""" @@ -180,8 +182,9 @@ def ideal(self, gens, side="twosided"): 'adbc', 'bcda'] """ - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(self.succ_generators(side = side), gens) + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(gens, self.succ_generators(side=side), + structure=None, enumeration='naive') @cached_method def j_classes(self): diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 1165d70569a..6f40fe1888d 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -200,9 +200,11 @@ def __iter__(self, index_set=None, max_depth = float("inf")): """ if index_set is None: index_set = self.index_set() - from sage.combinat.backtrack import TransitiveIdealGraded - return TransitiveIdealGraded(lambda x: [x.f(i) for i in index_set], - self.module_generators, max_depth).__iter__() + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(self.module_generators, + lambda x: [x.f(i) for i in index_set], + structure=None, + max_depth=max_depth).breadth_first_search_iterator() @cached_method def q_dimension(self, q=None, prec=None, use_product=False): diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 9cf09243976..de674a62207 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -648,9 +648,9 @@ def phi(self, i): sage: C = crystals.AlcovePaths(['A',2],[1,1]) sage: [c.phi(1) for c in C] - [1, 2, 0, 1, 0, 0, 1, 0] - sage: [c.phi(2) for c in C] [1, 0, 2, 0, 1, 1, 0, 0] + sage: [c.phi(2) for c in C] + [1, 2, 0, 1, 0, 0, 1, 0] """ highest_weight_crystal = self.parent()._highest_weight_crystal positions, gi = self._gi(i) @@ -672,9 +672,9 @@ def epsilon(self, i): sage: C = crystals.AlcovePaths(['A',2],[1,1]) sage: [c.epsilon(1) for c in C] - [0, 0, 1, 1, 0, 2, 0, 1] - sage: [c.epsilon(2) for c in C] [0, 1, 0, 0, 1, 0, 2, 1] + sage: [c.epsilon(2) for c in C] + [0, 0, 1, 1, 0, 2, 0, 1] """ #crude but functional j = 0 diff --git a/src/sage/combinat/enumerated_sets.py b/src/sage/combinat/enumerated_sets.py index 16d24e01253..47c183c00e1 100644 --- a/src/sage/combinat/enumerated_sets.py +++ b/src/sage/combinat/enumerated_sets.py @@ -113,11 +113,8 @@ Do we want a separate section, possibly more proeminent, for backtracking solvers? +- :func:`~sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet` - :class:`~sage.combinat.backtrack.GenericBacktracker` -- :class:`~sage.combinat.backtrack.TransitiveIdeal` -- :class:`~sage.combinat.backtrack.TransitiveIdealGraded` -- :func:`~sage.combinat.tools.transitive_ideal` -- :class:`~sage.combinat.backtrack.SearchForest` - :ref:`sage.combinat.tiling` - :ref:`sage.combinat.dlx` - :ref:`sage.combinat.matrices.dlxcpp` diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index f604fa84ac7..a5c39dc9164 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -318,9 +318,10 @@ def __iter__(self): [[2], [3]] """ index_set = self._cartan_type.classical().index_set() - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(lambda x: [x.f(i) for i in index_set], - self.module_generators).__iter__() + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(self.module_generators, + lambda x: [x.f(i) for i in index_set], + structure=None).naive_search_iterator() def module_generator(self, i=None, **options): r""" diff --git a/src/sage/combinat/rigged_configurations/rigged_configurations.py b/src/sage/combinat/rigged_configurations/rigged_configurations.py index a4e91ed3b7d..536d848ff8a 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -498,9 +498,10 @@ def __iter__(self): """ index_set = self._cartan_type.classical().index_set() - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(lambda x: [x.f(i) for i in index_set], - self.module_generators).__iter__() + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(self.module_generators, + lambda x: [x.f(i) for i in index_set], + structure=None).naive_search_iterator() @lazy_attribute def module_generators(self): diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py index 8bc2c5578b1..440d06e8c6d 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py @@ -335,9 +335,10 @@ def __iter__(self): [[2], [4]] (X) [[1]] """ index_set = self._cartan_type.classical().index_set() - from sage.combinat.backtrack import TransitiveIdeal - return TransitiveIdeal(lambda x: [x.f(i) for i in index_set], - self.module_generators).__iter__() + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return RecursivelyEnumeratedSet(self.module_generators, + lambda x: [x.f(i) for i in index_set], + structure=None).naive_search_iterator() def _test_bijection(self, **options): r""" diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index 13520fe9034..96dab17e5c0 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -21,7 +21,7 @@ from sage.rings.infinity import infinity from sage.rings.arith import binomial import sage.combinat.ranker -from sage.combinat.backtrack import TransitiveIdeal +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.combinat.root_system.root_system import RootSystem from sage.combinat.root_system.dynkin_diagram import DynkinDiagram from sage.combinat.root_system.weyl_group import WeylGroup @@ -137,7 +137,7 @@ def elements(self): Those are constructed as the elements below the maximal elements of ``self`` in Bruhat order. - OUTPUT: a :class:`TransitiveIdeal` object + OUTPUT: a :class:`RecursivelyEnumeratedSet_generic` object EXAMPLES:: @@ -150,9 +150,11 @@ def elements(self): .. TODO:: Possibly remove this method and instead have this class - inherit from :class:`TransitiveIdeal`. + inherit from :class:`RecursivelyEnumeratedSet_generic`. """ - return TransitiveIdeal(attrcall('bruhat_lower_covers'), self.maximal_elements()) + return RecursivelyEnumeratedSet(self.maximal_elements(), + attrcall('bruhat_lower_covers'), structure=None, + enumeration='naive') def __iter__(self): r""" diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 4446b4eea16..dd015a6e8ff 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -25,7 +25,7 @@ from sage.rings.all import ZZ, QQ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector -from sage.combinat.backtrack import TransitiveIdeal, TransitiveIdealGraded +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.combinat.root_system.plot import PlotOptions, barycentric_projection_matrix class RootLatticeRealizations(Category_over_base_ring): @@ -688,8 +688,9 @@ def positive_roots(self, index_set=None): " affine Cartan types") if index_set is None: index_set = tuple(self.cartan_type().index_set()) - return TransitiveIdealGraded(attrcall('pred', index_set=index_set), - [self.simple_root(i) for i in index_set]) + return RecursivelyEnumeratedSet([self.simple_root(i) for i in index_set], + attrcall('pred', index_set=index_set), + structure=None, enumeration='breadth') @cached_method def nonparabolic_positive_roots(self, index_set = None): @@ -786,7 +787,9 @@ def positive_real_roots(self): alpha[0] + alpha[1] + 2*alpha[2]] """ if self.cartan_type().is_finite(): - return tuple(TransitiveIdealGraded(attrcall('pred'), self.simple_roots())) + return tuple(RecursivelyEnumeratedSet(self.simple_roots(), + attrcall('pred'), structure=None, + enumeration='breadth')) if not self.cartan_type().is_affine(): raise NotImplementedError("only implemented for finite and affine Cartan types") @@ -933,7 +936,8 @@ def parabolic_covers(alpha): return [x for x in alpha.pred() if x.is_parabolic_root(index_set)] generators = [x for x in self.simple_roots() if x.is_parabolic_root(index_set)] - return TransitiveIdealGraded(parabolic_covers, generators) + return RecursivelyEnumeratedSet(generators, parabolic_covers, + structure=None, enumeration='breadth') @cached_method def positive_roots_nonparabolic(self, index_set = None): @@ -1184,7 +1188,7 @@ def negative_roots(self): raise ValueError("%s is not a finite Cartan type"%(self.cartan_type())) from sage.combinat.combinat import MapCombinatorialClass return MapCombinatorialClass(self.positive_roots(), attrcall('__neg__'), "The negative roots of %s"%self) - # Todo: use this instead once TransitiveIdeal will be a proper enumerated set + # Todo: use this instead once RecursivelyEnumeratedSet will be a proper enumerated set #return self.positive_roots().map(attrcall('__negate__')) ########################################################################## @@ -2789,7 +2793,7 @@ def alcove_label(w): # def neighbors(x): # return filter(lambda y: plot_options.bounding_box.contains(plot_options.origin_projected+y), # [immutable_vector(x+epsilon*t) for t in translation_vectors for epsilon in [-1,1]]) - # alcoves_shift = list(TransitiveIdeal(neighbors, [immutable_vector(plot_options.origin_projected)])) + # alcoves_shift = list(RecursivelyEnumeratedSet([immutable_vector(plot_options.origin_projected)], neighbors)) # else: # alcoves_shift = [sum(x*v for x,v in zip(alcove, translation_vectors)) # for alcove in alcoves] @@ -3130,7 +3134,9 @@ def orbit(self): sage: len(L.fundamental_weights()[2].orbit()) 6 """ - return [x for x in TransitiveIdealGraded(attrcall('simple_reflections'), [self])] + R = RecursivelyEnumeratedSet([self], attrcall('simple_reflections'), + structure=None, enumeration='breadth') + return list(R) ########################################################################## # @@ -3513,7 +3519,8 @@ def greater(self): sage: sorted([len(x.greater()) for x in L.rho().orbit()]) [1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 8, 8, 12, 12, 12, 24] """ - return [x for x in TransitiveIdeal(attrcall('succ'), [self])] + R = RecursivelyEnumeratedSet([self], attrcall('succ'), structure=None) + return list(R.naive_search_iterator()) def smaller(self): r""" @@ -3533,7 +3540,8 @@ def smaller(self): sage: sorted([len(x.smaller()) for x in L.rho().orbit()]) [1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 8, 8, 12, 12, 12, 24] """ - return [x for x in TransitiveIdeal(attrcall('pred'), [self])] + R = RecursivelyEnumeratedSet([self], attrcall('pred'), structure=None) + return list(R.naive_search_iterator()) ########################################################################## # Level diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index e6c8a9255bb..8c8d4b08e4b 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -161,11 +161,9 @@ def __contains__(self, element): """ return element in self.set() - @cached_method - def set(self): + def __iter__(self): r""" - Naive algorithm to give a set with all the elements of the conjugacy - class. + Naive algorithm to give the elements of the conjugacy class. .. TODO:: @@ -175,6 +173,44 @@ def set(self): EXAMPLES: + Groups of permutations:: + + sage: G = SymmetricGroup(3) + sage: g = G((1,2)) + sage: C = ConjugacyClass(G,g) + sage: sorted(C) + [(2,3), (1,2), (1,3)] + + It works for infinite groups:: + + sage: a = matrix(ZZ,2,[1,1,0,1]) + sage: b = matrix(ZZ,2,[1,0,1,1]) + sage: G = MatrixGroup([a,b]) # takes 1s + sage: g = G(a) + sage: C = ConjugacyClass(G, g) + sage: it = iter(C) + sage: [next(it) for _ in range(5)] + [ + [1 1] [ 0 1] [-1 1] [-1 4] [-5 9] + [0 1], [-1 2], [-4 3], [-1 3], [-4 7] + ] + + """ + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + g = self._representative + gens = self._parent.gens() + R = RecursivelyEnumeratedSet([g], + lambda y: [c*y*c**-1 for c in gens], + structure=None) + return R.breadth_first_search_iterator() + + @cached_method + def set(self): + r""" + Return the set of elements of the conjugacy class. + + EXAMPLES: + Groups of permutations:: sage: G = SymmetricGroup(3) @@ -200,16 +236,27 @@ def set(self): [[2, 2], [1, 0]], [[3, 1], [4, 4]]] sage: C.set() == Set(H(x) for x in S) True + + It is not implemented for infinite groups:: + + sage: a = matrix(ZZ,2,[1,1,0,1]) + sage: b = matrix(ZZ,2,[1,0,1,1]) + sage: G = MatrixGroup([a,b]) # takes 1s + sage: g = G(a) + sage: C = ConjugacyClass(G, g) + sage: C.set() + Traceback (most recent call last): + ... + NotImplementedError: Listing the elements of conjugacy classes is not implemented for infinite groups! Use the iter function instead. """ - from sage.sets.set import Set - from sage.combinat.backtrack import TransitiveIdeal if self._parent.is_finite(): - g = self._representative - G = self._parent - gens = G.gens() - return Set(x for x in TransitiveIdeal(lambda y: [c*y*c**-1 for c in gens], [g])) + from sage.sets.set import Set + return Set(iter(self)) + # return Set(self) creates an infinite loop in __contains__ else: - raise NotImplementedError("Listing the elements of conjugacy classes is not implemented for infinite groups!") + raise NotImplementedError("Listing the elements of conjugacy " + "classes is not implemented for infinite groups! Use the " + "iter function instead.") @cached_method def list(self): @@ -227,7 +274,14 @@ def list(self): sage: Set(L) == Set([G((1,3,2)), G((1,2,3))]) True """ - return list(self.set()) + if self._parent.is_finite(): + return list(iter(self)) + # return list(self) creates an infinite loop because list calls + # __len__ which calls list... + else: + raise NotImplementedError("Listing the elements of conjugacy " + "classes is not implemented for infinite groups! Use the " + "iter function instead.") def is_real(self): """ From f7a8d030c17eb00bb81a6fdf8c4cc561d51c18b8 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 3 Apr 2015 16:34:25 +0200 Subject: [PATCH 180/665] trac #18099: unimportant change in a doctest --- src/sage/coding/linear_code.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 85876347a58..1733d5b095f 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -717,20 +717,23 @@ def __init__(self, base_field, length): We first create a new LinearCode subclass:: sage: class CodeExample(sage.coding.linear_code.AbstractLinearCode): - ....: def __init__(self, field, length, dimension): + ....: def __init__(self, field, length, dimension, generator_matrix): ....: sage.coding.linear_code.AbstractLinearCode.__init__(self,field, length) ....: self._dimension = dimension + ....: self._generator_matrix = generator_matrix ....: def generator_matrix(self): - ....: return matrix(self.base_field(), self.dimension(), self.length(), {(i,i):1 for i in range(self.dimension())}) + ....: return self._generator_matrix ....: def _repr_(self): ....: return "Dummy code of length %d, dimension %d over %s" % (self.length(), self.dimension(), self.base_field()) We now create a member of our newly made class:: - sage: C = CodeExample(GF(17), 10, 5) + sage: generator_matrix = matrix(GF(17), 5, 10, + ....: {(i,i):1 for i in range(5)}) + sage: C = CodeExample(GF(17), 10, 5, generator_matrix) We can check its existence and parameters:: - + sage: C Dummy code of length 10, dimension 5 over Finite Field of size 17 From 357c4f6d37018740da2fc6117b8c5b257736d3d2 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Fri, 3 Apr 2015 19:18:54 +0200 Subject: [PATCH 181/665] Fixed too long doctest, put cached_method decorator over minimum_distance() and gens() methods --- src/sage/coding/linear_code.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 1733d5b095f..543f2458a8e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -750,8 +750,8 @@ def __init__(self, base_field, length): 1 sage: C.is_self_orthogonal() False - sage: print C.is_permutation_equivalent(C.dual_code()) #long time - True + sage: print C.divisor() #long time + 1 """ self._base_field = base_field self._length = length @@ -1782,6 +1782,7 @@ def generator_matrix_systematic(self): gen_mat_systematic = deprecated_function_alias(17973, generator_matrix_systematic) + @cached_method def gens(self): r""" Returns the generators of this code as a list of vectors. @@ -2099,6 +2100,7 @@ def _magma_init_(self, magma): s = 'LinearCode(%s)' % G return s + @cached_method def minimum_distance(self, algorithm=None): r""" Returns the minimum distance of this linear code. From 3a2328b9ee01824ca47991d70fa16d8e779c7600 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 3 Apr 2015 15:54:50 -0700 Subject: [PATCH 182/665] integrable representation, works for untwisted Type A --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/root_system/__init__.py | 1 + src/sage/combinat/root_system/all.py | 1 + .../root_system/integrable_representations.py | 321 ++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 src/sage/combinat/root_system/integrable_representations.py diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 66cb93a7d5f..0a17d02da3d 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -201,6 +201,7 @@ Comprehensive Module list sage/combinat/root_system/coxeter_matrix sage/combinat/root_system/dynkin_diagram sage/combinat/root_system/hecke_algebra_representation + sage/combinat/root_system/integrable_representations sage/combinat/root_system/non_symmetric_macdonald_polynomials sage/combinat/root_system/pieri_factors sage/combinat/root_system/plot diff --git a/src/sage/combinat/root_system/__init__.py b/src/sage/combinat/root_system/__init__.py index f7408099868..e762b391d15 100644 --- a/src/sage/combinat/root_system/__init__.py +++ b/src/sage/combinat/root_system/__init__.py @@ -62,6 +62,7 @@ --------------------- - :ref:`sage.combinat.root_system.weyl_characters` +- :ref:`sage.combinat.root_system.integrable_representations` - :ref:`sage.combinat.root_system.branching_rules` - :ref:`sage.combinat.root_system.hecke_algebra_representation` - :ref:`sage.combinat.root_system.non_symmetric_macdonald_polynomials` diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 69271d70073..763ea787cfe 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -14,3 +14,4 @@ from weyl_characters import WeylCharacterRing, WeightRing from branching_rules import BranchingRule, branching_rule_from_plethysm, branching_rule lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials') +from integrable_representations import IntegrableRepresentation diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py new file mode 100644 index 00000000000..8036acc8a5c --- /dev/null +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -0,0 +1,321 @@ +""" +Integrable Representations of Affine Lie Algebras +""" +#***************************************************************************** +# Copyright (C) 2014 Daniel Bump +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.structure.sage_object import SageObject +from sage.structure.unique_representation import UniqueRepresentation +from cartan_type import CartanType +from sage.rings.all import ZZ, QQ +from sage.misc.all import cached_method +from root_space import RootSpace +from weight_space import WeightSpace + +class IntegrableRepresentation(): + """ + This is a class for an irreducible representation of affine Lie algebras. + + INPUT: + + - ``Lam`` - a dominant weight in an extended weight lattice of affine type. + + OPTIONAL: + + - ``depth`` - a parameter indicating how far to push computations. + + REFERENCES: + + .. [Kac] Kac, *Infinite-dimensional Lie algebras*, Third Edition. + Cambridge, 1990. + + .. [KMPS] Kass, Moody, Patera and Slansky, Affine Lie algebras, + weight multiplicities, and branching rules. Vols. 1, 2. University of + California Press, Berkeley, CA, 1990. + + .. [KacPeterson] Kac and Peterson. Infinite-dimensional Lie algebras, theta + functions and modular forms. Adv. in Math. 53 (1984), no. 2, 125-264. + + If `\Lambda` is a dominant integral weight for an affine root system, there exists a unique + integrable representation of highest weight `\Lambda`. If `\mu` is another weight such that + `\Lambda-\mu` is in the root lattice, then multiplicity of `\mu` in this representation will + be denoted `m(\mu)`. + + Let `\delta` be the nullroot. Then for fixed `\mu` the function `m(\mu-k\delta)` is + a monotone increasing function of `\mu`. It is useful to take `\mu` to be such that this + function is nonzero if and only if `k\ge 0`. Therefore we make the following definition. + If `\mu` is such that `m(\mu)\\ne 0` but `m(\mu+\delta)=0` then `\mu` is called *maximal*. + + Since `\delta` is fixed under the action of the affine Weyl group, + and since the weight multiplicities are Weyl group invariant, the *string + function* `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` is replaced by an equivalent + weight. Therefore in tabulating the string functions, we may assume that `\mu` + is dominant. There are only a finite number of dominant maximal weights. + + Since every nonzero weight multiplicity appears in the string `\mu-k\delta` for + one of the finite number of dominant maximal weights `\mu`, it is important to + be able to compute these. We may do this as follows. + + EXAMPLE:: + + sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).strings() + 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 + 2*Lambda[0] + Lambda[2]: 4 31 161 665 2380 7658 22721 63120 166085 417295 1007601 2349655 + Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 + Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + + In this example, we construct the extended weight lattice of Cartan type ['A',3,1], + then define ``Lambda`` to be the fundamental weights. We find there are 5 maximal + dominant weights in irreducible representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, + and we determine their string functions. If you want more values, give IntegrableRepresentation + the optional parameter ``depth``, which defaults to 12. + + It was shown by Kac and Peterson that each string function is the set of + Fourier coefficients of a modular form. + + Every weight `\mu` such that the weight multiplicity `m(\mu)` is nonzero has the + form + + .. MATH:: + \Lambda - n_0\\alpha_0 - n_1\\alpha_1 - \cdots, + + where the `n_i` are nonnegative integers. This is represented internally as a + tuple ``(n0, n1, n2, ...)``. If you want an individual multiplicity you use + the method ``m`` and supply it with this tuple. The ``IntegrableRepresentation`` + class has methods ``to_weight`` and ``from_weight`` to convert between this + internal representation and the weight lattice:: + + sage: v = IntegrableRepresentation(2*Lambda[0]); v + The IntegrableRepresentation of ['A', 3, 1] with highest weight 2*Lambda[0] + sage: v.m((5,4,3,2)) + 11 + sage: delta = v._delta + sage: v.from_weight(-2*Lambda[0] + 4*Lambda[3] - 5*delta) + (5, 4, 3, 2) + + To get more values, use the depth parameter:: + + sage: sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 + Lambda[0] + sage: IntegrableRepresentation(4*L0, depth=20).strings() + 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 + 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 + 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 + + .. WARNING: + + Currently this code works only for untwisted Type A. + + """ + def __init__(self, Lam, depth=12, debug=False, new=True): + self._depth = depth + self._P = Lam.parent() + self._RS = self._P.root_system + self._Q = self._RS.root_lattice() + self._Lam = self._P(Lam) + self._cartan_matrix = self._RS.cartan_matrix() + self._cartan_type = self._RS.cartan_type() + self._classical_rank = self._cartan_type.classical().rank() + self._Lambda = self._P.fundamental_weights() + self._W = self._P.weyl_group(prefix="s") + self._s = self._W.simple_reflections() + self._index_set = self._P.index_set() + self._alpha = {} + for i in self._index_set: + self._alpha[i]=self._P(self._RS.root_lattice().simple_root(i)) + self._rho = self._P.rho() + self._delta = self._P.null_root() + self._shift = {} + self._smat = {} + for i in self._index_set: + for j in self._index_set: + self._smat[(i,j)] = -self._cartan_matrix[i][j] + self._smat[(i,i)] += 1 + for i in self._index_set: + self._shift[i] = tuple([ZZ((self._Lam-self._Lam.weyl_action(self._s[i])).symmetric_form(self._Lambda[j])) for j in self._index_set]) + self._ddict = {} + self._mdict = {tuple(0 for i in self._index_set):1} + if debug: + self._debug = 1 + else: + self._debug = None + self._new = new + self._den0 = (self._Lam+self._rho).symmetric_form(self._Lam+self._rho) + def from_classical_root(h): + """ + Coerces a classical root into P. + """ + index_set_classical = [i for i in self._index_set if i != 0] + return sum(self._alpha[i]*h.monomial_coefficients().get(i,0) for i in index_set_classical) + self._classical_roots = [from_classical_root(al) for al in self._Q.classical().roots()] + self._classical_positive_roots = [from_classical_root(al) for al in self._Q.classical().positive_roots()] + self.string(Lam) + + def __repr__(self): + return "The IntegrableRepresentation of %s with highest weight %s"%(self._cartan_type, self._Lam) + + def to_weight(self, n): + """ + returns `Lam - \sum n[i]*alpha[i]` + """ + return self._Lam - sum(ZZ(n[i])*self._alpha[i] for i in self._index_set) + + def from_weight(self, mu): + """ + returns `(n[0], n[1], ...)` such that `mu = Lam - \sum n[i]*alpha[i]` + """ + return tuple([ZZ((self._Lam-mu).symmetric_form(self._Lambda[i])) for i in self._index_set]) + + def s(self, n, i): + """ + Implements the `i`-th simple reflection in the internal representation of + weights by tuples. + """ + ret = [n[j] for j in self._index_set] + for j in self._index_set: + ret[j] += self._shift[i][j] + ret[i] -= sum(n[j]*self._cartan_matrix[i][j] for j in self._index_set) + return tuple(ret) + + def to_dominant(self, n): + """ + Returns the dominant weight equivalent to ``n`` in the internal + representation of weights by tuples. + """ + + if self._ddict.has_key(n): + return self._ddict[n] + for i in self._index_set: + m = self.s(n, i) + if m[i] < n[i]: + v = self.to_dominant(m) + self._ddict[n] = v + return v + return n + + def _freudenthal_roots_imaginary(self, nu): + """ + It is assumed that `\\nu` is in the root lattice `Q`. Returns the set of + imaginary roots `\\alpha\in\Delta^+` such that `\\nu+\\alpha\in Q^+`. + """ + kp = min(ZZ(nu.symmetric_form(self._Lambda[i])) for i in self._index_set) + return [u*self._delta for u in range(1,kp+1)] + + def _freudenthal_roots_real(self, nu): + """ + It is assumed that `nu` is in `Q`. Returns the set of realroots + `\alpha\in\Delta^+` such that `nu+\alpha\in Q^+`. + """ + ret = [] + for al in self._classical_positive_roots: + if all((nu-al).symmetric_form(self._Lambda[i])>=0 for i in self._index_set): + ret.append(al) + for al in self._classical_roots: + for ir in self._freudenthal_roots_imaginary(nu-al): + ret.append(al+ir) + return ret + + def _freudenthal_accum(self, nu, al): + """ + Helper function for ``self.m_freudenthal``. + """ + if self._debug: + print "g: nu=%s, a=%s"%(nu, al) + ret = 0 + k = 1 + while 1: + mk = self.m(self.from_weight(nu+k*al)) + sf = al.symmetric_form(nu+k*al) + if self._debug: + print "h: k=%s, m(nu+k*al)=%s, (a|nu+k*al)=%s"%(k, mk, sf) + if mk == 0: + break + ret += 2*mk*sf + k += 1 + return ret + + def _m_freudenthal(self, n): + """ + Computes the weight multiplicity using the Freudenthal multiplicity formula. + """ + if min(n)<0: + return 0 + if self._mdict.has_key(n): + return self._mdict[n] + mu = self.to_weight(n) + den = self._den0-(mu+self._rho).symmetric_form(mu+self._rho) + num = 0 + if self._debug: + print "f:", self._Lam-mu + for al in self._freudenthal_roots_real(self._Lam-mu): + num += self._freudenthal_accum(mu, al) + for al in self._freudenthal_roots_imaginary(self._Lam-mu): + num += self._classical_rank*self._freudenthal_accum(mu, al) + if den == 0 or self._debug: + print "i: num=%s, den=%s"%(num,den) + if self._debug: + print " e:%s,%s,%s"%(n.__repr__(), num, den) + return num/den + + def m(self, n): + """ + Returns the multiplicity + """ + if self._mdict.has_key(n): + return self._mdict[n] + elif self._ddict.has_key(n): + self._mdict[n] = self.m(self._ddict[n]) + m = self.to_dominant(n) + ret = self._m_freudenthal(m) + self._mdict[n] = ret + return ret + + def dominant_maximal(self): + """ + Returns the finite set of dominant maximal weights. + """ + ret = set() + for x in self._ddict.values(): + if self.m(x) > 0: + if min(x) == 0: + ret.add(x) + else: + y = tuple([u-1 for u in x]) + if self.m(y) == 0: + ret.add(y) + return [self.to_weight(x) for x in ret] + + def string(self, max): + """ + INPUT: + + - ``max`` - a dominant maximal weight. + + Returns the list of multiplicities ``m(max-k*delta)` + for ``k = 0,1,2,`` up to ``self._depth``. + """ + + ret = [] + k = self._depth + for j in range(k): + ret.append(self.m(self.from_weight(max-j*self._delta))) + return ret + + def strings(self): + """ + Returns the set of dominant maximal weights of self, together with the string + coefficients for each. + """ + for max in self.dominant_maximal(): + s = self.string(max) + print "%s:"%max, + for j in s: + print j, + print + From 8905552948a0896a46e587815cce539b6e60aae9 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 7 Apr 2015 10:08:07 +0200 Subject: [PATCH 183/665] Minor changes to documentation --- src/sage/coding/linear_code.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 543f2458a8e..1c6a00c81e5 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -706,6 +706,10 @@ def __init__(self, base_field, length): """ Initializes mandatory parameters for a Linear Code object. + This method only exists for inheritance purposes as it initializes + parameters that need to be known by every linear code. An abstract + linear code object should never be created. + INPUT: - ``base_field`` -- the base field of ``self`` From 2855780a8fcbe3ff4a60c377dbb6a49c31d11d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 7 Apr 2015 14:10:29 +0200 Subject: [PATCH 184/665] trac 18XXX method to test if Tamari interval is new --- src/sage/combinat/binary_tree.py | 46 ++++++++++++++++++++++++++++ src/sage/combinat/interval_posets.py | 19 ++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 2bdcca72b8f..392be353863 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1972,6 +1972,52 @@ def tamari_succ(self): [B([g, self[1]]) for g in self[0].tamari_succ()] + [B([self[0], d]) for d in self[1].tamari_succ()]) + def possible_cut_shapes(self): + """ + Return the list of possible cut shapes for the binary tree. + + This is used in :meth:`sage.combinat.interval_posets.TamariIntervalPoset.is_new`. + + OUTPUT: + + a list of triples `(m, i, n)` of integers + + This is a list running over all inner edges of the binary + tree. The removal of each inner edge defines two binary trees, + the root-tree and the sub-tree. + + Here `m` is the node number of the root-tree `R`, `n` the node + number of the sub-tree `S`. The integer `i` is the index of + the leaf of `R` on which `S` was grafted. The leaves of `R` are + numbered starting from `1`, hence `1 leq i \ leq m+1`. + + In fact, each of `m` and `n` determines the other, as the + total node number is the node number of ``self``. + + EXAMPLES:: + + sage: BT = BinaryTrees(3) + sage: [t.possible_cut_shapes() for t in BT] + [[(2, 3, 1), (1, 2, 2)], + [(2, 2, 1), (1, 2, 2)], + [(2, 1, 1), (2, 3, 1)], + [(2, 2, 1), (1, 1, 2)], + [(2, 1, 1), (1, 1, 2)]] + """ + resu = [] + left, right = list(self) + L = left.node_number() + R = right.node_number() + if L: + resu += [(m + R + 1, i, n) + for m, i, n in left.possible_cut_shapes()] + resu += [(R + 1, 1, L)] + if R: + resu += [(m + L + 1, i + L + 1, n) + for m, i, n in right.possible_cut_shapes()] + resu += [(L + 1, L + 2, R)] + return resu + def q_hook_length_fraction(self, q=None, q_factor=False): r""" Compute the ``q``-hook length fraction of the binary tree ``self``, diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 109f2a14795..0977a55caaf 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -2041,6 +2041,25 @@ def number_of_tamari_inversions(self): """ return len(self.tamari_inversions()) + def is_new(self): + """ + Return ``True`` if ``self`` is a new Tamari interval. + + Here 'new' means that the interval is not contained in any proper + facet of the associahedra. + + They have been considered in [ChapTamari08]_. + + EXAMPLES:: + + sage: TIP4 = TamariIntervalPosets(4) + sage: len([u for u in TIP4 if u.is_new()]) + 12 + """ + c_up = self.upper_binary_tree().possible_cut_shapes() + c_down = self.lower_binary_tree().possible_cut_shapes() + return not any(x in c_up for x in c_down) + # Abstract class to serve as a Factory ; no instances are created. class TamariIntervalPosets(UniqueRepresentation, Parent): From 7f667634d5f463ebc2cfb11ade42bb034d631402 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 8 Apr 2015 11:29:11 +0200 Subject: [PATCH 185/665] Fixed mistake in __cmp__ and changed docstring of AbstractLinearCode --- src/sage/coding/linear_code.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 1c6a00c81e5..42ccd2b8133 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -701,6 +701,35 @@ class AbstractLinearCode(module.Module): and on Linear Codes families. So, every Linear Code-related class should inherit from this abstract method. + + This class provides: + + - ``base_field``, the base field over which the code is defined + + - ``length``, the length of the code + + - numerous methods that will work for any linear code (including families) + + To implement a linear code, you need to: + + - inherit from AbstractLinearCode + + - call AbstractLinearCode ``__init__`` method in the subclass constructor. Example: + ``super(SubclassName, self).__init__(base_field, length)``. + By doing that, your subclass will have its ``base_field`` and ``length`` parameters + initialized and will be properly set as a member of the category framework. + You need of course to complete the constructor by adding any additional parameter + needed to describe properly the code defined in the subclass. + + As AbstractLinearCode is not designed to be implemented, it does not have any representation + methods. You should implement ``_repr_`` and ``_latex_`` methods on the sublclass. + + NOTE:: + + AbstractLinearCode embeds some generic implementations of helper methods like ``__cmp__`` or ``__eq__``. + As they are designed to fit for every linear code, they mostly use the generator matrix + and thus can be long for certain families of code. In that case, overriding these methods is encouraged. + """ def __init__(self, base_field, length): """ @@ -1269,7 +1298,7 @@ def __cmp__(self, right): """ if not isinstance(right, LinearCode): return cmp(type(self), type(right)) - return cmp(self._generator_matrix, right._generator_matrix) + return cmp(self.generator_matrix(), right.generator_matrix()) def parity_check_matrix(self): r""" From 1652d7c6f5dfc558d3f0b56882e2f51b7d82decb Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 8 Apr 2015 11:33:20 +0200 Subject: [PATCH 186/665] Small fixes in AbstractLinearCode docstring --- src/sage/coding/linear_code.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 42ccd2b8133..550985fa2e1 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -700,7 +700,7 @@ class AbstractLinearCode(module.Module): This class contains all methods that can be used on Linear Codes and on Linear Codes families. So, every Linear Code-related class should inherit from this abstract - method. + class. This class provides: @@ -722,7 +722,7 @@ class AbstractLinearCode(module.Module): needed to describe properly the code defined in the subclass. As AbstractLinearCode is not designed to be implemented, it does not have any representation - methods. You should implement ``_repr_`` and ``_latex_`` methods on the sublclass. + methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. NOTE:: From b287c3b3ce8715d3bf73a1e7d1faa139ccf2c72a Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 9 Apr 2015 09:05:00 +0200 Subject: [PATCH 187/665] Generator matrix is now an abstract method --- src/sage/coding/linear_code.py | 39 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 550985fa2e1..87765bda3fd 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -721,6 +721,8 @@ class AbstractLinearCode(module.Module): You need of course to complete the constructor by adding any additional parameter needed to describe properly the code defined in the subclass. + - reimplement ``generator_matrix()`` method + As AbstractLinearCode is not designed to be implemented, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. @@ -1772,26 +1774,7 @@ def __getitem__(self, i): return codeword def generator_matrix(self): - r""" - Return a generator matrix of this code. - - EXAMPLES:: - - sage: C1 = codes.HammingCode(3,GF(2)) - sage: C1.generator_matrix() - [1 0 0 0 0 1 1] - [0 1 0 0 1 0 1] - [0 0 1 0 1 1 0] - [0 0 0 1 1 1 1] - sage: C2 = codes.HammingCode(2,GF(4,"a")) - sage: C2.generator_matrix() - [ 1 0 0 a + 1 a] - [ 0 1 0 1 1] - [ 0 0 1 a a + 1] - """ - return self._generator_matrix - - gen_mat = deprecated_function_alias(17973, generator_matrix) + return NotImplementedError("This method must be set in subclasses") def generator_matrix_systematic(self): """ @@ -3306,3 +3289,19 @@ def _repr_(self): Linear code of length 7, dimension 4 over Finite Field of size 2 """ return "Linear code of length %s, dimension %s over %s"%(self.length(), self.dimension(), self.base_ring()) + + def generator_matrix(self): + r""" + Return a generator matrix of this code. + + EXAMPLES:: + + sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1]) + sage: code = LinearCode(G) + sage: code.generator_matrix() + [1 2 1] + [2 1 1] + """ + return self._generator_matrix + + gen_mat = deprecated_function_alias(17973, generator_matrix) From 9b6d9b31dfd797c9324918ad5ad52576110a59cf Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 9 Apr 2015 09:07:52 +0200 Subject: [PATCH 188/665] Removed _gens attribute from linear code and changed gens() method accordingly --- src/sage/coding/linear_code.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 87765bda3fd..fded51ad893 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -1809,10 +1809,7 @@ def gens(self): sage: C.gens() [(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)] """ - if hasattr(self, "_gens"): - return self._gens - else: - return self.generator_matrix().rows() + return self.generator_matrix().rows() def genus(self): r""" @@ -3271,7 +3268,6 @@ def __init__(self, generator_matrix, d=None): raise ValueError("this linear code contains no non-zero vector") super(LinearCode, self).__init__(base_ring, generator_matrix.ncols()) - self._gens = generator_matrix.rows() self._generator_matrix = generator_matrix self._dimension = generator_matrix.rank() self._minimum_distance = d From 7f8558df2cff74b659b569502c2068518c84c4f0 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 9 Apr 2015 11:53:58 +0200 Subject: [PATCH 189/665] Removed _base_field parameter and changed base_field method --- src/sage/coding/linear_code.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index fded51ad893..71052e3bb64 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -716,7 +716,7 @@ class AbstractLinearCode(module.Module): - call AbstractLinearCode ``__init__`` method in the subclass constructor. Example: ``super(SubclassName, self).__init__(base_field, length)``. - By doing that, your subclass will have its ``base_field`` and ``length`` parameters + By doing that, your subclass will have its ``length`` parameter initialized and will be properly set as a member of the category framework. You need of course to complete the constructor by adding any additional parameter needed to describe properly the code defined in the subclass. @@ -726,7 +726,7 @@ class AbstractLinearCode(module.Module): As AbstractLinearCode is not designed to be implemented, it does not have any representation methods. You should implement ``_repr_`` and ``_latex_`` methods in the sublclass. - NOTE:: + .. NOTE:: AbstractLinearCode embeds some generic implementations of helper methods like ``__cmp__`` or ``__eq__``. As they are designed to fit for every linear code, they mostly use the generator matrix @@ -788,11 +788,9 @@ def __init__(self, base_field, length): sage: print C.divisor() #long time 1 """ - self._base_field = base_field self._length = length cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() - facade_for = VectorSpace(self._base_field, self._length) - self.Element = type(facade_for.an_element()) # for when we make this a non-facade parent + facade_for = VectorSpace(base_field, self._length) Parent.__init__(self, base=base_field, facade=facade_for, category=cat) def _an_element_(self): @@ -994,7 +992,7 @@ def base_field(self): sage: C.base_field() Finite Field of size 2 """ - return self._base_field + return self.base_ring() def basis(self): r""" From 6fc5eb18f749e4ee36af0203e22d13a67e2a5fe4 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 9 Apr 2015 11:59:58 +0200 Subject: [PATCH 190/665] Small fix to the documentation of AbstractLinearCode --- src/sage/coding/linear_code.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 71052e3bb64..46fb920f7da 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -704,8 +704,6 @@ class AbstractLinearCode(module.Module): This class provides: - - ``base_field``, the base field over which the code is defined - - ``length``, the length of the code - numerous methods that will work for any linear code (including families) From afc9fce253e82eb3f57041bb1ed3c0691e35881f Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 9 Apr 2015 13:41:37 +0200 Subject: [PATCH 191/665] Reinstated self.Element = ... line in abstract class constructor --- src/sage/coding/linear_code.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 46fb920f7da..56c42fd52e9 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -789,6 +789,7 @@ def __init__(self, base_field, length): self._length = length cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() facade_for = VectorSpace(base_field, self._length) + self.Element = type(facade_for.an_element()) #for when we made this a non-facade parent Parent.__init__(self, base=base_field, facade=facade_for, category=cat) def _an_element_(self): From eccce0202c0a7773f5238af3e5b23f7706e6ff21 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Fri, 10 Apr 2015 15:20:29 +0200 Subject: [PATCH 192/665] added doctests for zeta series representation around 1 --- src/sage/functions/transcendental.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 0ebc901e825..24c888c73b2 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -76,6 +76,13 @@ def __init__(self): sage: a = zeta(2,hold=True); a.simplify() 1/6*pi^2 + Check that :trac:`15846` is resolved:: + + sage: zeta(x).series(x==1, 1) + 1*(x - 1)^(-1) + (euler_gamma + log(2) + log(pi) + 2*zetaderiv(1, 0)) + Order(x - 1) + sage: zeta(x).residue(x==1) + 1 + TESTS:: sage: latex(zeta(x)) From f3733a7f4f6f0d6ea45b4c222bb57d6dde454d49 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 10 Apr 2015 13:55:22 -0700 Subject: [PATCH 193/665] now working for all untwisted types, but slower than previous commmit. --- .../root_system/integrable_representations.py | 216 ++++++++++++------ 1 file changed, 141 insertions(+), 75 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 8036acc8a5c..c85613cc67c 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -15,6 +15,7 @@ from sage.misc.all import cached_method from root_space import RootSpace from weight_space import WeightSpace +from sage.functions.other import floor class IntegrableRepresentation(): """ @@ -69,6 +70,10 @@ class IntegrableRepresentation(): Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(Lambda[0]+Lambda[1]).strings() # long time + Lambda[3] + Lambda[4] - delta: 3 25 136 590 2205 7391 22780 65613 178660 463842 1155717 2777795 + Lambda[0] + Lambda[1]: 1 10 62 293 1165 4097 13120 38997 109036 289575 735870 1799620 In this example, we construct the extended weight lattice of Cartan type ['A',3,1], then define ``Lambda`` to be the fundamental weights. We find there are 5 maximal @@ -87,34 +92,38 @@ class IntegrableRepresentation(): where the `n_i` are nonnegative integers. This is represented internally as a tuple ``(n0, n1, n2, ...)``. If you want an individual multiplicity you use - the method ``m`` and supply it with this tuple. The ``IntegrableRepresentation`` - class has methods ``to_weight`` and ``from_weight`` to convert between this - internal representation and the weight lattice:: + the method ``m`` and supply it with this tuple:: + sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]); v - The IntegrableRepresentation of ['A', 3, 1] with highest weight 2*Lambda[0] - sage: v.m((5,4,3,2)) - 11 + The IntegrableRepresentation of ['C', 2, 1] with highest weight 2*Lambda[0] + sage: v.m((3,5,3)) + 18 + + The ``IntegrableRepresentation`` class has methods ``to_weight`` and ``from_weight`` + to convert between this internal representation and the weight lattice:: + sage: delta = v._delta - sage: v.from_weight(-2*Lambda[0] + 4*Lambda[3] - 5*delta) - (5, 4, 3, 2) + sage: v.to_weight((4,3,2)) + -3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta + sage: v.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) + (4, 3, 2) To get more values, use the depth parameter:: - sage: sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 + sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 Lambda[0] sage: IntegrableRepresentation(4*L0, depth=20).strings() 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 - .. WARNING: - - Currently this code works only for untwisted Type A. - """ def __init__(self, Lam, depth=12, debug=False, new=True): self._depth = depth + if debug: + self._debug_depth = 0 + self._debug = debug self._P = Lam.parent() self._RS = self._P.root_system self._Q = self._RS.root_lattice() @@ -126,51 +135,101 @@ def __init__(self, Lam, depth=12, debug=False, new=True): self._W = self._P.weyl_group(prefix="s") self._s = self._W.simple_reflections() self._index_set = self._P.index_set() - self._alpha = {} - for i in self._index_set: - self._alpha[i]=self._P(self._RS.root_lattice().simple_root(i)) + self._index_set_classical = [i for i in self._index_set if i != 0] + self._alpha = self._Q.simple_roots() + self._alphacheck = self._Q.simple_coroots() self._rho = self._P.rho() - self._delta = self._P.null_root() - self._shift = {} + cmi = self._cartan_type.classical().cartan_matrix().inverse() + self._cminv = {} + for i in self._index_set_classical: + for j in self._index_set_classical: + self._cminv[(i,j)] = cmi[i-1][j-1] self._smat = {} for i in self._index_set: for j in self._index_set: self._smat[(i,j)] = -self._cartan_matrix[i][j] self._smat[(i,i)] += 1 + self._shift = {} for i in self._index_set: - self._shift[i] = tuple([ZZ((self._Lam-self._Lam.weyl_action(self._s[i])).symmetric_form(self._Lambda[j])) for j in self._index_set]) + self._shift[i] = self._Lam.scalar(self._alphacheck[i]) self._ddict = {} self._mdict = {tuple(0 for i in self._index_set):1} - if debug: - self._debug = 1 - else: - self._debug = None self._new = new self._den0 = (self._Lam+self._rho).symmetric_form(self._Lam+self._rho) def from_classical_root(h): """ Coerces a classical root into P. """ - index_set_classical = [i for i in self._index_set if i != 0] - return sum(self._alpha[i]*h.monomial_coefficients().get(i,0) for i in index_set_classical) + return sum(self._alpha[i]*h.monomial_coefficients().get(i,0) for i in self._index_set_classical) self._classical_roots = [from_classical_root(al) for al in self._Q.classical().roots()] self._classical_positive_roots = [from_classical_root(al) for al in self._Q.classical().positive_roots()] - self.string(Lam) + self._eps = {} + for i in self._index_set: + self._eps[i] = self._cartan_type.a()[i]/self._cartan_type.dual().a()[i] + self._delta = sum(self._cartan_type.a()[i]*self._alpha[i] for i in self._index_set) + self.string(self._Lam) def __repr__(self): return "The IntegrableRepresentation of %s with highest weight %s"%(self._cartan_type, self._Lam) + def parent(self): + return self._P + + def inner_qq(self, qelt1, qelt2): + """ + Symmetric form between two elements of the root lattice. + + .. WARNING: + + If ``qelt1`` or ``qelt1`` accidentally gets coerced into + the extended weight lattice, this will return an answer, + and it will be wrong. To make this code robust, parents + should be checked. This is not done since in the application + the parents are known, so checking would unnecessarily slow + us down. + """ + return sum(qelt1.monomial_coefficients().get(i,0)*qelt2.monomial_coefficients().get(j,0)* \ + self._cartan_matrix[i][j]/self._eps[i] for i in self._index_set for j in self._index_set) + + def inner_pq(self, pelt, qelt): + """ + Symmetric form between an element of the weight and root lattices + + .. WARNING: + + If ``qelt`` accidentally gets coerced into the extended weight + lattice, this will return an answer, and it will be wrong. To make + this code robust, parents should be checked. This is not done + since in the application the parents are known, so checking would + unnecessarily slow us down. + + """ + return sum(pelt.monomial_coefficients().get(i,0)*qelt.monomial_coefficients().get(i,0)/self._eps[i] for i in self._index_set) + def to_weight(self, n): """ returns `Lam - \sum n[i]*alpha[i]` """ return self._Lam - sum(ZZ(n[i])*self._alpha[i] for i in self._index_set) + def _from_weight_helper(self, mu): + """ + It is assumeed that mu is in the root lattice. + returns `(n[0], n[1], ...)` such that `mu = \sum n[i]*alpha[i]` + """ + mu = self._P(mu) + n0 = mu.monomial_coefficients().get('delta',0) + mu0 = mu - n0*self._P(self._alpha[0]) + ret = [n0] + for i in self._index_set_classical: + ret.append(sum(self._cminv[(i,j)]*mu0.monomial_coefficients().get(j,0) for j in self._index_set_classical)) + return tuple(ZZ(i) for i in ret) + def from_weight(self, mu): """ returns `(n[0], n[1], ...)` such that `mu = Lam - \sum n[i]*alpha[i]` """ - return tuple([ZZ((self._Lam-mu).symmetric_form(self._Lambda[i])) for i in self._index_set]) + return self._from_weight_helper(self._Lam - mu) def s(self, n, i): """ @@ -178,90 +237,94 @@ def s(self, n, i): weights by tuples. """ ret = [n[j] for j in self._index_set] - for j in self._index_set: - ret[j] += self._shift[i][j] + ret[i] += self._Lam.monomial_coefficients().get(i,0) ret[i] -= sum(n[j]*self._cartan_matrix[i][j] for j in self._index_set) return tuple(ret) def to_dominant(self, n): - """ - Returns the dominant weight equivalent to ``n`` in the internal - representation of weights by tuples. - """ - if self._ddict.has_key(n): return self._ddict[n] + mc = self.to_weight(n).monomial_coefficients() for i in self._index_set: - m = self.s(n, i) - if m[i] < n[i]: + if mc.get(i,0) < 0: + m = self.s(n, i) v = self.to_dominant(m) self._ddict[n] = v return v return n - def _freudenthal_roots_imaginary(self, nu): - """ - It is assumed that `\\nu` is in the root lattice `Q`. Returns the set of - imaginary roots `\\alpha\in\Delta^+` such that `\\nu+\\alpha\in Q^+`. + def freudenthal_roots_imaginary(self, nu): """ + It is assumed that `nu` is in `Q`. Returns the set of imaginary roots + `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. + kp = min(ZZ(nu.symmetric_form(self._Lambda[i])) for i in self._index_set) + return [u*self._delta for u in [1..kp]] + """ + l = self._from_weight_helper(nu) + kp = min(floor(l[i]/self._cartan_type.a()[i]) for i in self._index_set) return [u*self._delta for u in range(1,kp+1)] - def _freudenthal_roots_real(self, nu): + def freudenthal_roots_real(self, nu): """ - It is assumed that `nu` is in `Q`. Returns the set of realroots - `\alpha\in\Delta^+` such that `nu+\alpha\in Q^+`. + It is assumed that `nu` is in `Q`. Returns the set of real positive + roots `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. """ ret = [] for al in self._classical_positive_roots: - if all((nu-al).symmetric_form(self._Lambda[i])>=0 for i in self._index_set): + if all(x>=0 for x in self._from_weight_helper(nu-al)): ret.append(al) for al in self._classical_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): + for ir in self.freudenthal_roots_imaginary(nu-al): ret.append(al+ir) return ret - def _freudenthal_accum(self, nu, al): + def freudenthal_roots(self, nu): """ - Helper function for ``self.m_freudenthal``. + It is assumed that `nu` is in `Q`. Returns the set of realroots + `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. + + This code is not called in the main algorithm. """ - if self._debug: - print "g: nu=%s, a=%s"%(nu, al) + ret = [] + for alpha in self.freudenthal_roots_imaginary(nu): + ret.append(alpha) + for alpha in self.freudenthal_roots_real(nu): + ret.append(alpha) + return ret + + def _freudenthal_accum(self, nu, al): ret = 0 k = 1 while 1: - mk = self.m(self.from_weight(nu+k*al)) - sf = al.symmetric_form(nu+k*al) - if self._debug: - print "h: k=%s, m(nu+k*al)=%s, (a|nu+k*al)=%s"%(k, mk, sf) - if mk == 0: + if min(self._from_weight_helper(self._Lam-nu-k*al))<0: break - ret += 2*mk*sf + mk = self.m(self.from_weight(nu+k*al)) + ip = self.inner_pq(nu+k*al,al) + ret += 2*mk*ip k += 1 return ret - def _m_freudenthal(self, n): + def m_freudenthal(self, n): """ Computes the weight multiplicity using the Freudenthal multiplicity formula. """ if min(n)<0: return 0 - if self._mdict.has_key(n): - return self._mdict[n] mu = self.to_weight(n) - den = self._den0-(mu+self._rho).symmetric_form(mu+self._rho) + al = sum(n[i]*self._alpha[i] for i in self._index_set) + den = 2*self.inner_pq(self._Lam+self._rho, al)-self.inner_qq(al,al) num = 0 - if self._debug: - print "f:", self._Lam-mu - for al in self._freudenthal_roots_real(self._Lam-mu): + for al in self.freudenthal_roots_real(self._Lam-mu): num += self._freudenthal_accum(mu, al) - for al in self._freudenthal_roots_imaginary(self._Lam-mu): + for al in self.freudenthal_roots_imaginary(self._Lam-mu): num += self._classical_rank*self._freudenthal_accum(mu, al) - if den == 0 or self._debug: - print "i: num=%s, den=%s"%(num,den) - if self._debug: - print " e:%s,%s,%s"%(n.__repr__(), num, den) - return num/den + if den == 0 and num == 0: + print "m_freudenthal","m: n=%s, num=den=0"%n.__repr__() + try: + return ZZ(num/den) + except: + return None def m(self, n): """ @@ -272,8 +335,13 @@ def m(self, n): elif self._ddict.has_key(n): self._mdict[n] = self.m(self._ddict[n]) m = self.to_dominant(n) - ret = self._m_freudenthal(m) - self._mdict[n] = ret + if self._mdict.has_key(m): + return self._mdict[m] + ret = self.m_freudenthal(m) + if ret is not None: + self._mdict[n] = ret + else: + print "m: error - failed to compute m%s"%n.__repr__() return ret def dominant_maximal(self): @@ -286,9 +354,9 @@ def dominant_maximal(self): if min(x) == 0: ret.add(x) else: - y = tuple([u-1 for u in x]) + y = self.from_weight(self.to_weight(x)+self._delta) if self.m(y) == 0: - ret.add(y) + ret.add(x) return [self.to_weight(x) for x in ret] def string(self, max): @@ -297,10 +365,9 @@ def string(self, max): - ``max`` - a dominant maximal weight. - Returns the list of multiplicities ``m(max-k*delta)` + Returns the list of multiplicities ``m(max-k*delta)`` for ``k = 0,1,2,`` up to ``self._depth``. """ - ret = [] k = self._depth for j in range(k): @@ -318,4 +385,3 @@ def strings(self): for j in s: print j, print - From 2db2621f9a89086ec1792a5ccc1748cc0e7c4761 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sat, 11 Apr 2015 10:04:10 +0200 Subject: [PATCH 194/665] 18155: upgrade to pynac-0.3.3 --- build/pkgs/pynac/checksums.ini | 6 +++--- build/pkgs/pynac/package-version.txt | 2 +- src/sage/functions/other.py | 2 +- src/sage/matrix/matrix_symbolic_dense.pyx | 2 +- src/sage/misc/functional.py | 4 ++-- src/sage/symbolic/expression.pyx | 7 ++++--- src/sage/tests/french_book/calculus_doctest.py | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/build/pkgs/pynac/checksums.ini b/build/pkgs/pynac/checksums.ini index b2e6a7c42f1..d38bc102a67 100644 --- a/build/pkgs/pynac/checksums.ini +++ b/build/pkgs/pynac/checksums.ini @@ -1,4 +1,4 @@ tarball=pynac-VERSION.tar.bz2 -sha1=d7a80f5c96eec3ac9ecb6757d004e460fbfecece -md5=70fae63e2c1cb4ec13eea24a4a780ba8 -cksum=1408069708 +sha1=76fea7a56a14d52eb2d14aaf11e21598bd68a8b4 +md5=1bbb82164082440cf87bb83d28b056b3 +cksum=3562766241 diff --git a/build/pkgs/pynac/package-version.txt b/build/pkgs/pynac/package-version.txt index d15723fbe8d..1c09c74e221 100644 --- a/build/pkgs/pynac/package-version.txt +++ b/build/pkgs/pynac/package-version.txt @@ -1 +1 @@ -0.3.2 +0.3.3 diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 209f98d44df..cec0f310e72 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -267,7 +267,7 @@ def __init__(self): sage: sqrt(x^2) sqrt(x^2) sage: abs(sqrt(x)) - abs(sqrt(x)) + sqrt(abs(x)) sage: complex(abs(3*I)) (3+0j) diff --git a/src/sage/matrix/matrix_symbolic_dense.pyx b/src/sage/matrix/matrix_symbolic_dense.pyx index 6d74d0c3cfa..151ee06d6c5 100644 --- a/src/sage/matrix/matrix_symbolic_dense.pyx +++ b/src/sage/matrix/matrix_symbolic_dense.pyx @@ -210,7 +210,7 @@ cdef class Matrix_symbolic_dense(matrix_generic_dense.Matrix_generic_dense): sage: eval, [evec], mult = es[0] sage: delta = eval*evec - evec*A sage: abs(abs(delta)) < 1e-10 - abs(sqrt(1/25*(3*(2*sqrt(3)*sqrt(2) - 3)*(sqrt(6) - 2) + 16*sqrt(3)*sqrt(2) + 5*sqrt(6) - 54)^2 + 1/25*(3*(sqrt(6) - 2)*(sqrt(6) - 4) + 14*sqrt(3)*sqrt(2) + 4*sqrt(6) - 42)^2 + 144/25*(sqrt(3)*sqrt(2) - sqrt(6))^2)) < (1.00000000000000e-10) + sqrt(abs(1/25*(3*(2*sqrt(3)*sqrt(2) - 3)*(sqrt(6) - 2) + 16*sqrt(3)*sqrt(2) + 5*sqrt(6) - 54)^2 + 1/25*(3*(sqrt(6) - 2)*(sqrt(6) - 4) + 14*sqrt(3)*sqrt(2) + 4*sqrt(6) - 42)^2 + 144/25*(sqrt(3)*sqrt(2) - sqrt(6))^2)) < (1.00000000000000e-10) sage: abs(abs(delta)).n() < 1e-10 True diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index e8d634704b5..bb3328f1bdf 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -1029,10 +1029,10 @@ def norm(x): sage: v = vector([-1,2,3]) sage: norm(v) sqrt(14) - sage: _ = var("a b c d") + sage: _ = var("a b c d", domain='real') sage: v = vector([a, b, c, d]) sage: norm(v) - sqrt(abs(a)^2 + abs(b)^2 + abs(c)^2 + abs(d)^2) + sqrt(a^2 + b^2 + c^2 + d^2) The norm of matrices:: diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index f8be9fd7c00..2f72444bb82 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -8955,10 +8955,10 @@ cdef class Expression(CommutativeRingElement): This tests that :trac:`11668` has been fixed (by :trac:`12780`):: - sage: a,b = var('a b') + sage: a,b = var('a b', domain='real') sage: A = abs((a+I*b))^2 sage: A.canonicalize_radical() - abs(a + I*b)^2 + a^2 + b^2 sage: imag(A) 0 sage: imag(A.canonicalize_radical()) @@ -10432,8 +10432,9 @@ cdef class Expression(CommutativeRingElement): EXAMPLES:: + sage: x = var('x', domain='real') sage: s = abs((1+I*x)^4); s - abs((I*x + 1)^4) + (I*x + 1)^2*(-I*x + 1)^2 sage: s._plot_fast_callable(x) sage: s._plot_fast_callable(x)(10) diff --git a/src/sage/tests/french_book/calculus_doctest.py b/src/sage/tests/french_book/calculus_doctest.py index ed5186d5acd..febef586355 100644 --- a/src/sage/tests/french_book/calculus_doctest.py +++ b/src/sage/tests/french_book/calculus_doctest.py @@ -100,7 +100,7 @@ Sage example in ./calculus.tex, line 318:: sage: f = sqrt(abs(x)^2); f.canonicalize_radical() - abs(x) + x sage: f = log(x*y); f.canonicalize_radical() log(x) + log(y) From d18bbbd756c90649933d3cf216fbebe571838e73 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:34:01 +0200 Subject: [PATCH 195/665] interactive_constructors_c: rst fixes --- src/sage/ext/interactive_constructors_c.pyx | 66 ++++++++++++--------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/sage/ext/interactive_constructors_c.pyx b/src/sage/ext/interactive_constructors_c.pyx index dd8af9778e8..d6051edcb25 100644 --- a/src/sage/ext/interactive_constructors_c.pyx +++ b/src/sage/ext/interactive_constructors_c.pyx @@ -1,5 +1,6 @@ -# Optional versions of certain ring constructors that automatically -# inject variables into the global module scope. +r""" +Constructors that automatically inject variables into the global module scope +""" import sage.rings.all @@ -18,11 +19,12 @@ def inject_on(verbose=True): variables into the global namespace. INPUT: - verbose -- (default: True) if True, print which constructors - become interactive, and also print variables as - they are implicitly defined. - EXAMPLES: + - verbose (default: True) if True, print which constructors become + interactive, and also print variables as they are implicitly defined. + + EXAMPLES:: + sage: inject_on(verbose=True) Redefining: FiniteField Frac FractionField FreeMonoid GF LaurentSeriesRing NumberField PolynomialRing quo quotient sage: GF(9,'b') @@ -46,20 +48,22 @@ def inject_on(verbose=True): ROLL YOUR OWN: If a constructor you would like to auto inject variables isn't made to do so by running this command your options are: - (1) Make your own constructor (factory function) using the explicit - inject_variables() method. This is *very* easy: - sage: def poly(*args, **kwds): - ... R = PolynomialRing(*args, **kwds) - ... R.inject_variables() - ... return R - sage: R = poly(QQ, 'z') - Defining z - sage: z^3 + 3 - z^3 + 3 + 1. Make your own constructor (factory function) using the explicit + ``inject_variables()`` method. This is *very* easy:: + + sage: def poly(*args, **kwds): + ....: R = PolynomialRing(*args, **kwds) + ....: R.inject_variables() + ....: return R + sage: R = poly(QQ, 'z') + Defining z + sage: z^3 + 3 + z^3 + 3 + + 2. Add code to do it to src/sage/ext/interactive_constructors_c.pyx, + rebuild Sage (with sage -br), and send a patch to sage-devel ``:-)``. - (2) Add code to do it to src/sage/ext/interactive_constructors_c.pyx, - rebuild Sage (with sage -br), and send a patch to sage-devel :-). """ global _verbose _verbose = verbose @@ -104,7 +108,7 @@ def FiniteField(*args, **kwds): Construct a finite field and inject the variables of the finite field to the global interactive interpreter. Use inject=False to not inject the variables. This is a wrapper - around the following function: <<>> + around the following function: FiniteField """ t = _do_inject(kwds) R = sage.rings.all.FiniteField(*args, **kwds) @@ -117,9 +121,10 @@ def FractionField(*args, **kwds): Construct the fraction field of a field and inject the generators of the fraction field to the global interactive interpreter. Use inject=False to not inject the variables. This is a wrapper - around the following function: <<>> + around the following function: FractionField + + EXAMPLES (that illustrate interactive injection of variables):: - EXAMPLES (that illustrate interactive injection of variables): sage: inject_on(verbose=False) sage: Frac(QQ['x']) Fraction Field of Univariate Polynomial Ring in x over Rational Field @@ -136,13 +141,14 @@ Frac = FractionField def FreeMonoid(*args, **kwds): """ Construct a free monoid and inject the variables of the monoid - into the global interactive interpreter. Use inject=Fale to not + into the global interactive interpreter. Use inject=False to not inject the variables. This is a wrapper around the following - function: <<>> + function: FreeMonoid EXAMPLES: + We illustrate creating a free monoid with and without injecting - the variables into the interpreter. + the variables into the interpreter:: sage: inject_on(verbose=False) sage: FreeMonoid(4,'x') @@ -167,7 +173,7 @@ def LaurentSeriesRing(*args, **kwds): inject=False to not inject the variables. This is a wrapper around the following function: - <<>> + LaurentSeries """ t = _do_inject(kwds) R = sage.rings.all.LaurentSeriesRing(*args, **kwds) @@ -179,7 +185,7 @@ def NumberField(*args, **kwds): fraction field into the interpreters global namespace. Use inject=False to not inject the variables. This is a wrapper around the following function: - <<>> + NumberField """ t = _do_inject(kwds) R = sage.rings.all.NumberField(*args, **kwds) @@ -190,7 +196,8 @@ def quotient(R, I, names, inject=True): Construct the quotient R/I and name the generators, which are then injected into the module scope (if inject=True). - EXAMPLES: + EXAMPLES:: + sage: inject_on(verbose=False) sage: R = PolynomialRing(QQ, 'x,y') sage: S = quo(R, (x^3, x^2 + y^2), 'a,b') @@ -216,11 +223,12 @@ def PolynomialRing(*args, **kwds): Construct a polynomial ring and inject the variables of the polynomial ring to the global interactive interpreter. Use inject=False to not inject the variables. This is a wrapper - around the following function: <<>> + around the following function: PolynomialRing MORE EXAMPLES: + We illustrate creating a polynomial ring without injecting the variables - into the interpreter. + into the interpreter:: sage: inject_on(verbose=False) sage: PolynomialRing(QQ,'w') From 2a69693bc8ec5424539c270fc8c218c421964611 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:23:00 +0200 Subject: [PATCH 196/665] Ref: add missing modules to r/{plotting,plot3d} Also sphinxify or fix their docstrings as necessary for the reference manual to build (but not necessarily to look good). --- src/doc/en/reference/plot3d/index.rst | 7 ++++ src/doc/en/reference/plotting/index.rst | 1 + src/sage/plot/misc.py | 2 + src/sage/plot/plot3d/{help.pyx => help.py} | 0 src/sage/plot/plot3d/implicit_surface.pyx | 2 +- src/sage/plot/plot3d/shapes.pyx | 16 ++++---- src/sage/plot/plot3d/transform.pyx | 2 + src/sage/plot/plot3d/tri_plot.py | 48 ++++++++++++---------- 8 files changed, 47 insertions(+), 31 deletions(-) rename src/sage/plot/plot3d/{help.pyx => help.py} (100%) diff --git a/src/doc/en/reference/plot3d/index.rst b/src/doc/en/reference/plot3d/index.rst index cb490a17478..16cbae41e7a 100644 --- a/src/doc/en/reference/plot3d/index.rst +++ b/src/doc/en/reference/plot3d/index.rst @@ -19,4 +19,11 @@ sage/plot/plot3d/texture sage/plot/plot3d/index_face_set + sage/plot/java3d + sage/plot/plot3d/help + sage/plot/plot3d/implicit_surface + sage/plot/plot3d/shapes + sage/plot/plot3d/transform + sage/plot/plot3d/tri_plot + .. include:: ../footer.txt diff --git a/src/doc/en/reference/plotting/index.rst b/src/doc/en/reference/plotting/index.rst index 6d0f5ac5650..eb2dd48109e 100644 --- a/src/doc/en/reference/plotting/index.rst +++ b/src/doc/en/reference/plotting/index.rst @@ -31,5 +31,6 @@ sage/plot/colors sage/plot/hyperbolic_arc sage/plot/hyperbolic_polygon + sage/plot/misc .. include:: ../footer.txt diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index 0a2ad7cc380..c7a303bb586 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -1,3 +1,5 @@ +"Plotting utilities" + #***************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) # diff --git a/src/sage/plot/plot3d/help.pyx b/src/sage/plot/plot3d/help.py similarity index 100% rename from src/sage/plot/plot3d/help.pyx rename to src/sage/plot/plot3d/help.py diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index c542af23b4c..bf4c8c0f9e8 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1061,7 +1061,7 @@ cdef class ImplicitSurface(IndexFaceSet): """ Return a representation of this object in the .obj format. - TESTS:: + TESTS: We graph a simple plane:: diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 6ec5cb0c208..72b31fec644 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -165,10 +165,10 @@ def ColorCube(size, colors, opacity=1, **kwds): INPUT: - - size -- 3-tuple of sizes (same as for box and frame) - - colors -- a list of either 3 or 6 colors - - opacity -- (default: 1) opacity of cube sides - - **kwds -- passed to the face constructor + - ``size`` -- 3-tuple of sizes (same as for box and frame) + - ``colors`` -- a list of either 3 or 6 colors + - ``opacity`` -- (default: 1) opacity of cube sides + - ``**kwds`` -- passed to the face constructor OUTPUT: @@ -366,7 +366,7 @@ cdef class Cylinder(ParametricSurface): self.height) def tachyon_repr(self, render_params): - """ + r""" EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cylinder @@ -404,7 +404,7 @@ cdef class Cylinder(ParametricSurface): return cyl def jmol_repr(self, render_params): - """ + r""" EXAMPLES:: sage: from sage.plot.plot3d.shapes import Cylinder @@ -710,7 +710,7 @@ cdef class Sphere(ParametricSurface): return ""%(self.radius) def tachyon_repr(self, render_params): - """ + r""" Tachyon can natively handle spheres. Ellipsoids rendering is done as a parametric surface. @@ -743,7 +743,7 @@ cdef class Sphere(ParametricSurface): return "Sphere center %s %s %s Rad %s %s" % (cen[0], cen[1], cen[2], rad, self.texture.id) def jmol_repr(self, render_params): - """ + r""" EXAMPLES:: sage: from sage.plot.plot3d.shapes import Sphere diff --git a/src/sage/plot/plot3d/transform.pyx b/src/sage/plot/plot3d/transform.pyx index e4f11db18a5..027ccb9443d 100644 --- a/src/sage/plot/plot3d/transform.pyx +++ b/src/sage/plot/plot3d/transform.pyx @@ -1,3 +1,5 @@ +"Transformations" + #***************************************************************************** # Copyright (C) 2007 Robert Bradshaw # diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index f8037631665..5d670907038 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -2,13 +2,16 @@ Adaptive refinement code for 3d surface plotting AUTHOR: - -- Tom Boothby -- Algorithm design, code - -- Joshua Kantor -- Algorithm design - -- Marshall Hampton -- Docstrings and doctests + +- Tom Boothby -- Algorithm design, code +- Joshua Kantor -- Algorithm design +- Marshall Hampton -- Docstrings and doctests TODO: - -- Parametrizations (cylindrical, spherical) - -- Massive optimization + +- Parametrizations (cylindrical, spherical) +- Massive optimization +""" ########################################################################### # Copyright (C) 2007 Tom Boothby @@ -19,11 +22,9 @@ ########################################################################### -""" - from sage.plot.colors import hue from math import sqrt -from random import random +import random class Triangle: """ @@ -124,7 +125,7 @@ def str(self): Returns a string representation of the SmoothTriangle of the form a b c color da db dc - + where a, b, and c are the triangle corner coordinates, da, db, dc are normals at each corner, and color is the color. @@ -155,10 +156,10 @@ class TriangleFactory: def triangle(self, a, b, c, color = None): """ Parameters: - a, b, c : triples (x,y,z) representing corners on a triangle in 3-space + a, b, c : triples (x,y,z) representing corners on a triangle in 3-space Returns: - a Triangle object with the specified coordinates + a Triangle object with the specified coordinates TESTS:: @@ -176,11 +177,12 @@ def triangle(self, a, b, c, color = None): def smooth_triangle(self, a, b, c, da, db, dc, color = None): """ Parameters: - a, b, c : triples (x,y,z) representing corners on a triangle in 3-space - da, db, dc : triples (dx,dy,dz) representing the normal vector at each point a,b,c + + - a, b, c : triples (x,y,z) representing corners on a triangle in 3-space + - da, db, dc : triples (dx,dy,dz) representing the normal vector at each point a,b,c Returns: - a SmoothTriangle object with the specified coordinates and normals + a SmoothTriangle object with the specified coordinates and normals TESTS:: @@ -198,12 +200,13 @@ def smooth_triangle(self, a, b, c, da, db, dc, color = None): def get_colors(self, list): """ Parameters: - list: an iterable collection of values which can be cast into colors -- typically an - RGB triple, or an RGBA 4-tuple + list: an iterable collection of values which can be cast into colors + -- typically an RGB triple, or an RGBA 4-tuple Returns: - a list of single parameters which can be passed into the set_color method of the - Triangle or SmoothTriangle objects generated by this factory. + a list of single parameters which can be passed into the set_color + method of the Triangle or SmoothTriangle objects generated by this + factory. TESTS:: @@ -305,6 +308,7 @@ def fcn(x,y): def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, ne_z, mid_z, depth): """ Recursive triangulation function for plotting. + First six inputs are scalars, next 5 are 2-dimensional lists, and the depth argument keeps track of the depth of recursion. @@ -387,10 +391,10 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, else: ne_depth = self._max_depth - qtr1_x = min_x + (.325 + random()/4)*(mid_x-min_x) - qtr3_x = mid_x + (.325 + random()/4)*(max_x-mid_x) - qtr1_y = min_y + (.325 + random()/4)*(mid_y-min_y) - qtr3_y = mid_y + (.325 + random()/4)*(max_y-mid_y) + qtr1_x = min_x + (.325 + random.random()/4)*(mid_x-min_x) + qtr3_x = mid_x + (.325 + random.random()/4)*(max_x-mid_x) + qtr1_y = min_y + (.325 + random.random()/4)*(mid_y-min_y) + qtr3_y = mid_y + (.325 + random.random()/4)*(max_y-mid_y) # function evaluated at the midpoints (possibly random) mid_sw_z = self._fcn(qtr1_x,qtr1_y) From 03070400f6175b16c6d94541b5a410048eadbb09 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sat, 11 Apr 2015 17:36:10 +0200 Subject: [PATCH 197/665] 15047: doctest; fixed in pynac-0.3.3 --- src/sage/symbolic/ring.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index d883c622d91..16255f9264a 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -400,6 +400,13 @@ cdef class SymbolicRing(CommutativeRing): True sage: f.subs(pattern == x^2) arctan(x^2) + + TESTS: + + Check that :trac:`15048` is fixed:: + + sage: latex(SR.wild(0)) + \$0 """ return new_Expression_from_GEx(self, g_wild(n)) From 075776db349c9d2bcdc553d176fde2346fb0c056 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:23:00 +0200 Subject: [PATCH 198/665] Ref: add various missing modules to r/repl Also sphinxify or fix their docstrings as necessary for the reference manual to build (but not necessarily to look good). --- src/doc/en/reference/repl/index.rst | 16 ++++++++++++++-- src/sage/repl/display/jsmol_iframe.py | 4 ++-- src/sage/repl/image.py | 4 ++-- src/sage/repl/inputhook.pyx | 2 +- src/sage/repl/rich_output/backend_sagenb.py | 4 ++-- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/doc/en/reference/repl/index.rst b/src/doc/en/reference/repl/index.rst index 7a98831d350..b372d46c650 100644 --- a/src/doc/en/reference/repl/index.rst +++ b/src/doc/en/reference/repl/index.rst @@ -65,7 +65,6 @@ this works using a modified displayhook in Python. sage/repl/display/fancy_repr sage/repl/display/util - Display Backend Infrastructure ------------------------------ @@ -80,10 +79,23 @@ Display Backend Infrastructure sage/repl/rich_output/output_graphics3d sage/repl/rich_output/output_catalog - sage/repl/rich_output/backend_base + sage/repl/rich_output/backend_base sage/repl/rich_output/backend_test sage/repl/rich_output/backend_doctest sage/repl/rich_output/backend_ipython + sage/repl/rich_output/backend_sagenb + +Miscellaneous +------------- + +.. toctree:: + :maxdepth: 2 + + sage/ext/interactive_constructors_c + sage/repl/display/jsmol_iframe + sage/repl/image + sage/repl/inputhook + sage/repl/ipython_tests .. include:: ../footer.txt diff --git a/src/sage/repl/display/jsmol_iframe.py b/src/sage/repl/display/jsmol_iframe.py index 9ec9476c0ec..21263a4da27 100644 --- a/src/sage/repl/display/jsmol_iframe.py +++ b/src/sage/repl/display/jsmol_iframe.py @@ -167,7 +167,7 @@ def script(self): return ''.join(script) def js_script(self): - """ + r""" The :meth:`script` as Javascript string. Since the many shortcomings of Javascript include multi-line @@ -218,7 +218,7 @@ def inner_html(self): """ Return a HTML document containing a JSmol applet - OUTPUT: + OUTPUT:: sage: from sage.repl.display.jsmol_iframe import JSMolHtml sage: from sage.repl.rich_output.output_graphics3d import OutputSceneJmol diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 187205e8c79..34e065a094c 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -42,7 +42,7 @@ def __init__(self, mode, size, color=0): """ Creates a new image with the given mode and size. - INPUT:: + INPUT: - ``mode`` -- string. The mode to use for the new image. Valid options are: @@ -221,7 +221,7 @@ def height(self): return self.pil.size[1] def save(self, filename): - """ + r""" Save the bitmap image INPUT: diff --git a/src/sage/repl/inputhook.pyx b/src/sage/repl/inputhook.pyx index 4a64c6746b9..edef9717910 100644 --- a/src/sage/repl/inputhook.pyx +++ b/src/sage/repl/inputhook.pyx @@ -72,7 +72,7 @@ def uninstall(): def sage_inputhook(): - """ + r""" The input hook. This function will be called every 100ms when IPython is idle at diff --git a/src/sage/repl/rich_output/backend_sagenb.py b/src/sage/repl/rich_output/backend_sagenb.py index dc860e311e0..8d2dd157243 100644 --- a/src/sage/repl/rich_output/backend_sagenb.py +++ b/src/sage/repl/rich_output/backend_sagenb.py @@ -311,7 +311,7 @@ def supported_output(self): ]) def display_immediately(self, plain_text, rich_output): - """ + r""" Show output without waiting for the prompt. INPUT: @@ -331,7 +331,7 @@ def display_immediately(self, plain_text, rich_output): This method does not return anything. - EXAMPLES: + EXAMPLES:: sage: import sage.repl.rich_output.output_catalog as catalog sage: plain_text = catalog.OutputPlainText.example() From 14a582670d110610752bdfb4995b74f8291e4dcf Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 11 Apr 2015 13:23:09 -0700 Subject: [PATCH 199/665] First pass over code to clean up the interface and data. --- .../root_system/integrable_representations.py | 285 ++++++++++-------- 1 file changed, 158 insertions(+), 127 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index c85613cc67c..051fcc3624a 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -1,6 +1,7 @@ """ Integrable Representations of Affine Lie Algebras """ + #***************************************************************************** # Copyright (C) 2014 Daniel Bump # @@ -8,26 +9,30 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from cartan_type import CartanType +from sage.structure.category_object import CategoryObject +#from sage.structure.parent import Parent +from sage.categories.modules import Modules +from sage.combinat.root_system.cartan_type import CartanType from sage.rings.all import ZZ, QQ from sage.misc.all import cached_method from root_space import RootSpace from weight_space import WeightSpace from sage.functions.other import floor -class IntegrableRepresentation(): - """ - This is a class for an irreducible representation of affine Lie algebras. +# TODO: Make this a proper parent and implement actions +class IntegrableRepresentation(CategoryObject, UniqueRepresentation): + r""" + An irreducible highest weight representation of an affine Lie algebra. INPUT: - - ``Lam`` - a dominant weight in an extended weight lattice of affine type. + - ``Lam`` -- a dominant weight in an extended weight lattice + of affine type OPTIONAL: - - ``depth`` - a parameter indicating how far to push computations. + - ``depth`` -- a parameter indicating how far to push computations REFERENCES: @@ -41,25 +46,30 @@ class IntegrableRepresentation(): .. [KacPeterson] Kac and Peterson. Infinite-dimensional Lie algebras, theta functions and modular forms. Adv. in Math. 53 (1984), no. 2, 125-264. - If `\Lambda` is a dominant integral weight for an affine root system, there exists a unique - integrable representation of highest weight `\Lambda`. If `\mu` is another weight such that - `\Lambda-\mu` is in the root lattice, then multiplicity of `\mu` in this representation will + If `\Lambda` is a dominant integral weight for an affine root system, + there exists a unique integrable representation of highest weight + `\Lambda`. If `\mu` is another weight such that `\Lambda - \mu` is in + the root lattice, then multiplicity of `\mu` in this representation will be denoted `m(\mu)`. - Let `\delta` be the nullroot. Then for fixed `\mu` the function `m(\mu-k\delta)` is - a monotone increasing function of `\mu`. It is useful to take `\mu` to be such that this - function is nonzero if and only if `k\ge 0`. Therefore we make the following definition. - If `\mu` is such that `m(\mu)\\ne 0` but `m(\mu+\delta)=0` then `\mu` is called *maximal*. + Let `\delta` be the nullroot. Then for fixed `\mu` the function + `m(\mu - k\delta)` is a monotone increasing function of `\mu`. It is + useful to take `\mu` to be such that this function is nonzero if and + only if `k \geq 0`. Therefore we make the following definition. + If `\mu` is such that `m(\mu) \neq 0` but `m(\mu + \delta) = 0` + then `\mu` is called *maximal*. Since `\delta` is fixed under the action of the affine Weyl group, - and since the weight multiplicities are Weyl group invariant, the *string - function* `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` is replaced by an equivalent - weight. Therefore in tabulating the string functions, we may assume that `\mu` - is dominant. There are only a finite number of dominant maximal weights. + and since the weight multiplicities are Weyl group invariant, the + *string function* `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` + is replaced by an equivalent weight. Therefore in tabulating the + string functions, we may assume that `\mu` is dominant. There are + only a finite number of dominant maximal weights. - Since every nonzero weight multiplicity appears in the string `\mu-k\delta` for - one of the finite number of dominant maximal weights `\mu`, it is important to - be able to compute these. We may do this as follows. + Since every nonzero weight multiplicity appears in the string + `\mu - k\delta` for one of the finite number of dominant maximal + weights `\mu`, it is important to be able to compute these. We may + do this as follows. EXAMPLE:: @@ -75,35 +85,37 @@ class IntegrableRepresentation(): Lambda[3] + Lambda[4] - delta: 3 25 136 590 2205 7391 22780 65613 178660 463842 1155717 2777795 Lambda[0] + Lambda[1]: 1 10 62 293 1165 4097 13120 38997 109036 289575 735870 1799620 - In this example, we construct the extended weight lattice of Cartan type ['A',3,1], - then define ``Lambda`` to be the fundamental weights. We find there are 5 maximal - dominant weights in irreducible representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, - and we determine their string functions. If you want more values, give IntegrableRepresentation - the optional parameter ``depth``, which defaults to 12. + In this example, we construct the extended weight lattice of Cartan + type `A_3^{(1)}`, then define ``Lambda`` to be the fundamental + weights. We find there are 5 maximal dominant weights in irreducible + representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, + and we determine their string functions. - It was shown by Kac and Peterson that each string function is the set of - Fourier coefficients of a modular form. + It was shown by Kac and Peterson that each string function is the + set of Fourier coefficients of a modular form. - Every weight `\mu` such that the weight multiplicity `m(\mu)` is nonzero has the - form + Every weight `\mu` such that the weight multiplicity `m(\mu)` is + nonzero has the form .. MATH:: - \Lambda - n_0\\alpha_0 - n_1\\alpha_1 - \cdots, - where the `n_i` are nonnegative integers. This is represented internally as a - tuple ``(n0, n1, n2, ...)``. If you want an individual multiplicity you use - the method ``m`` and supply it with this tuple:: + \Lambda - n_0 \alpha_0 - n_1 \alpha_1 - \cdots, + + where the `n_i` are nonnegative integers. This is represented internally + as a tuple ``(n0, n1, n2, ...)``. If you want an individual multiplicity + you use the method ``m`` and supply it with this tuple:: sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]); v - The IntegrableRepresentation of ['C', 2, 1] with highest weight 2*Lambda[0] + Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] sage: v.m((3,5,3)) 18 - The ``IntegrableRepresentation`` class has methods ``to_weight`` and ``from_weight`` - to convert between this internal representation and the weight lattice:: + The :class:`IntegrableRepresentation` class has methods :meth:`to_weight` + and :meth:`from_weight` to convert between this internal representation + and the weight lattice:: - sage: delta = v._delta + sage: delta = v._Q.null_root() sage: v.to_weight((4,3,2)) -3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta sage: v.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) @@ -113,67 +125,69 @@ class IntegrableRepresentation(): sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 Lambda[0] - sage: IntegrableRepresentation(4*L0, depth=20).strings() + sage: IntegrableRepresentation(4*L0).strings(depth=20) 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 - """ - def __init__(self, Lam, depth=12, debug=False, new=True): - self._depth = depth - if debug: - self._debug_depth = 0 - self._debug = debug + def __init__(self, Lam): + """ + Initialize ``self``. + """ + CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ)) + + self._Lam = Lam self._P = Lam.parent() - self._RS = self._P.root_system - self._Q = self._RS.root_lattice() - self._Lam = self._P(Lam) - self._cartan_matrix = self._RS.cartan_matrix() - self._cartan_type = self._RS.cartan_type() + self._Q = self._P.root_system.root_lattice() + + self._cartan_matrix = self._P.root_system.cartan_matrix() + self._cartan_type = self._P.root_system.cartan_type() self._classical_rank = self._cartan_type.classical().rank() - self._Lambda = self._P.fundamental_weights() - self._W = self._P.weyl_group(prefix="s") - self._s = self._W.simple_reflections() self._index_set = self._P.index_set() - self._index_set_classical = [i for i in self._index_set if i != 0] - self._alpha = self._Q.simple_roots() - self._alphacheck = self._Q.simple_coroots() - self._rho = self._P.rho() + self._index_set_classical = self._cartan_type.classical().index_set() + cmi = self._cartan_type.classical().cartan_matrix().inverse() self._cminv = {} for i in self._index_set_classical: for j in self._index_set_classical: self._cminv[(i,j)] = cmi[i-1][j-1] + self._smat = {} for i in self._index_set: for j in self._index_set: self._smat[(i,j)] = -self._cartan_matrix[i][j] self._smat[(i,i)] += 1 + self._shift = {} + alphacheck = self._Q.simple_coroots() for i in self._index_set: - self._shift[i] = self._Lam.scalar(self._alphacheck[i]) + self._shift[i] = self._Lam.scalar(alphacheck[i]) + self._ddict = {} - self._mdict = {tuple(0 for i in self._index_set):1} - self._new = new - self._den0 = (self._Lam+self._rho).symmetric_form(self._Lam+self._rho) + self._mdict = {tuple(0 for i in self._index_set): 1} + + Lam_rho = self._Lam + self._P.rho() + self._den0 = Lam_rho.symmetric_form(Lam_rho) + def from_classical_root(h): """ - Coerces a classical root into P. + Coerces a classical root into Q. """ - return sum(self._alpha[i]*h.monomial_coefficients().get(i,0) for i in self._index_set_classical) - self._classical_roots = [from_classical_root(al) for al in self._Q.classical().roots()] - self._classical_positive_roots = [from_classical_root(al) for al in self._Q.classical().positive_roots()] + return self._Q._from_dict(h._monomial_coefficients) + self._classical_roots = [from_classical_root(al) + for al in self._Q.classical().roots()] + self._classical_positive_roots = [from_classical_root(al) + for al in self._Q.classical().positive_roots()] + self._eps = {} for i in self._index_set: - self._eps[i] = self._cartan_type.a()[i]/self._cartan_type.dual().a()[i] - self._delta = sum(self._cartan_type.a()[i]*self._alpha[i] for i in self._index_set) - self.string(self._Lam) + self._eps[i] = self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] def __repr__(self): - return "The IntegrableRepresentation of %s with highest weight %s"%(self._cartan_type, self._Lam) - - def parent(self): - return self._P + """ + Return a string representation of ``self``. + """ + return "Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) def inner_qq(self, qelt1, qelt2): """ @@ -202,39 +216,46 @@ def inner_pq(self, pelt, qelt): this code robust, parents should be checked. This is not done since in the application the parents are known, so checking would unnecessarily slow us down. - """ return sum(pelt.monomial_coefficients().get(i,0)*qelt.monomial_coefficients().get(i,0)/self._eps[i] for i in self._index_set) def to_weight(self, n): """ - returns `Lam - \sum n[i]*alpha[i]` + Return the weight associated to the tuple ``n``. + + If ``n`` is the tuple `(n_1, n_2, \ldots)`, then the associated + weight is `\Lambda - \sum_i n_i alpha_i`, where `\Lambda` is the + weight of the representation. """ - return self._Lam - sum(ZZ(n[i])*self._alpha[i] for i in self._index_set) + alpha = self._P.simple_roots() + I = self._index_set + return self._Lam - self._P.sum(ZZ(val) * alpha[I[i]] + for i,val in enumerate(n)) def _from_weight_helper(self, mu): """ - It is assumeed that mu is in the root lattice. - returns `(n[0], n[1], ...)` such that `mu = \sum n[i]*alpha[i]` + It is assumeed that ``mu`` is in the root lattice. + returns ``(n[0], n[1], ...)`` such that ``mu = \sum n[i]*alpha[i]`` """ mu = self._P(mu) - n0 = mu.monomial_coefficients().get('delta',0) - mu0 = mu - n0*self._P(self._alpha[0]) + n0 = mu.monomial_coefficients().get('delta', 0) + mu0 = mu - n0*self._P.simple_root(0) ret = [n0] for i in self._index_set_classical: - ret.append(sum(self._cminv[(i,j)]*mu0.monomial_coefficients().get(j,0) for j in self._index_set_classical)) + ret.append(sum(self._cminv[(i,j)]*mu0.monomial_coefficients().get(j,0) + for j in self._index_set_classical)) return tuple(ZZ(i) for i in ret) def from_weight(self, mu): """ - returns `(n[0], n[1], ...)` such that `mu = Lam - \sum n[i]*alpha[i]` + Return ``(n[0], n[1], ...)`` such that ``mu = Lam - \sum n[i]*alpha[i]`` """ return self._from_weight_helper(self._Lam - mu) def s(self, n, i): """ - Implements the `i`-th simple reflection in the internal representation of - weights by tuples. + Implements the `i`-th simple reflection in the internal + representation of weights by tuples. """ ret = [n[j] for j in self._index_set] ret[i] += self._Lam.monomial_coefficients().get(i,0) @@ -254,25 +275,28 @@ def to_dominant(self, n): return n def freudenthal_roots_imaginary(self, nu): - """ - It is assumed that `nu` is in `Q`. Returns the set of imaginary roots - `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. - - kp = min(ZZ(nu.symmetric_form(self._Lambda[i])) for i in self._index_set) - return [u*self._delta for u in [1..kp]] + r""" + It is assumed that ``nu`` is in `Q`. Returns the set of imaginary roots + `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. + + Lambda = self._P.fundamental_weights() + kp = min(ZZ(nu.symmetric_form(Lambda[i])) for i in self._index_set) + delta = self._Q.null_root() + return [u*delta for u in [1..kp]] """ l = self._from_weight_helper(nu) - kp = min(floor(l[i]/self._cartan_type.a()[i]) for i in self._index_set) - return [u*self._delta for u in range(1,kp+1)] + kp = min(floor(l[i] / self._cartan_type.a()[i]) for i in self._index_set) + delta = self._Q.null_root() + return [u*delta for u in range(1,kp+1)] def freudenthal_roots_real(self, nu): - """ - It is assumed that `nu` is in `Q`. Returns the set of real positive - roots `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. + r""" + It is assumed that ``nu`` is in `Q`. Returns the set of real positive + roots `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. """ ret = [] for al in self._classical_positive_roots: - if all(x>=0 for x in self._from_weight_helper(nu-al)): + if all(x >= 0 for x in self._from_weight_helper(nu-al)): ret.append(al) for al in self._classical_roots: for ir in self.freudenthal_roots_imaginary(nu-al): @@ -280,9 +304,9 @@ def freudenthal_roots_real(self, nu): return ret def freudenthal_roots(self, nu): - """ - It is assumed that `nu` is in `Q`. Returns the set of realroots - `\alpha\in\Delta^+` such that `nu-\alpha\in Q^+`. + r""" + It is assumed that ``nu`` is in `Q`. Returns the set of real roots + `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. This code is not called in the main algorithm. """ @@ -296,40 +320,41 @@ def freudenthal_roots(self, nu): def _freudenthal_accum(self, nu, al): ret = 0 k = 1 - while 1: - if min(self._from_weight_helper(self._Lam-nu-k*al))<0: - break - mk = self.m(self.from_weight(nu+k*al)) - ip = self.inner_pq(nu+k*al,al) + while min(self._from_weight_helper(self._Lam - nu - k*al)) >= 0: + mk = self.m(self.from_weight(nu + k*al)) + ip = self.inner_pq(nu + k*al, al) ret += 2*mk*ip k += 1 return ret def m_freudenthal(self, n): """ - Computes the weight multiplicity using the Freudenthal multiplicity formula. + Compute the weight multiplicity using the Freudenthal multiplicity formula. """ - if min(n)<0: + if min(n) < 0: return 0 mu = self.to_weight(n) - al = sum(n[i]*self._alpha[i] for i in self._index_set) - den = 2*self.inner_pq(self._Lam+self._rho, al)-self.inner_qq(al,al) + I = self._index_set + al = self._Q._from_dict({I[i]: val for i,val in enumerate(n) if val}, + remove_zeros=False) + den = 2*self.inner_pq(self._Lam+self._P.rho(), al) - self.inner_qq(al,al) num = 0 - for al in self.freudenthal_roots_real(self._Lam-mu): + for al in self.freudenthal_roots_real(self._Lam - mu): num += self._freudenthal_accum(mu, al) - for al in self.freudenthal_roots_imaginary(self._Lam-mu): + for al in self.freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank*self._freudenthal_accum(mu, al) if den == 0 and num == 0: print "m_freudenthal","m: n=%s, num=den=0"%n.__repr__() try: - return ZZ(num/den) + return ZZ(num / den) except: return None def m(self, n): """ - Returns the multiplicity + Return the multiplicity. """ + # TODO: Make this non-recursive by implementing our own stack if self._mdict.has_key(n): return self._mdict[n] elif self._ddict.has_key(n): @@ -346,42 +371,48 @@ def m(self, n): def dominant_maximal(self): """ - Returns the finite set of dominant maximal weights. + Return the finite set of dominant maximal weights. """ ret = set() + delta = self._Q.null_root() for x in self._ddict.values(): if self.m(x) > 0: if min(x) == 0: ret.add(x) else: - y = self.from_weight(self.to_weight(x)+self._delta) + y = self.from_weight(self.to_weight(x) + delta) if self.m(y) == 0: ret.add(x) return [self.to_weight(x) for x in ret] - def string(self, max): + def string(self, max_weight, depth=12): """ - INPUT: + Return the list of multiplicities `m(\Lambda - k \delta)` where + `\Lambda` is ``max_weight`` and `k` runs from `0` to ``depth``. - - ``max`` - a dominant maximal weight. + INPUT: - Returns the list of multiplicities ``m(max-k*delta)`` - for ``k = 0,1,2,`` up to ``self._depth``. + - ``max_weight`` -- a dominant maximal weight + - ``depth`` -- (default: 12) the maximum value of `k` """ ret = [] - k = self._depth - for j in range(k): - ret.append(self.m(self.from_weight(max-j*self._delta))) + delta = self._Q.null_root() + for k in range(depth): + ret.append(self.m( self.from_weight(max_weight - k*delta) )) return ret - def strings(self): + def strings(self, depth=12): """ - Returns the set of dominant maximal weights of self, together with the string - coefficients for each. + Return the set of dominant maximal weights of ``self``, together + with the string coefficients for each. """ - for max in self.dominant_maximal(): - s = self.string(max) - print "%s:"%max, + # FIXME: This call to string should not be necessary as it is + # highly redundant to generate the data for dominant_maximal + self.string(self._Lam, depth) + for max_weight in self.dominant_maximal(): + s = self.string(max_weight, depth) + print "%s:"%max_weight, for j in s: print j, print + From 155f26f5a21b2a4f14fb40d2128bee871c0e701a Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sat, 11 Apr 2015 18:09:58 -0400 Subject: [PATCH 200/665] deleted Ht->s and s->Ht, added Ht->m --- src/sage/combinat/sf/macdonald.py | 189 ++++++++++++++++++++++++------ 1 file changed, 154 insertions(+), 35 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 90b670b7887..b4c27e14d89 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -28,6 +28,10 @@ .. [LLM1998] L. Lapointe, A. Lascoux, J. Morse, Determinantal Expressions for Macdonald Polynomials, IRMN no. 18 (1998). :arXiv:`math/9808050`. + +.. [BH2013] Tableaux Formulas for Macdonald Polynomials, Special edition + in honour of Christophe Reutenauer 60 birthday, International Journal + of Algebra and Computation, Volume 23, Issue 4, (2013), pp. 833-852. """ #***************************************************************************** @@ -51,10 +55,12 @@ from sage.categories.homset import Hom import sfa import sage.combinat.partition +from sage.combinat.partition import Partition from sage.matrix.all import MatrixSpace from sage.rings.all import QQ from sage.misc.all import prod from sage.rings.fraction_field import FractionField +from sage.misc.cachefunc import cached_function import functools # cache in q,t globally and subs locally with q and t values @@ -68,8 +74,7 @@ _s_to_h_cache = {} #Ht basis cache -_ht_to_s_cache = {} -_s_to_ht_cache = {} +_ht_to_m_cache = {} #S basis cache _S_to_s_cache = {} @@ -611,6 +616,101 @@ def c2(part, q, t): res *= 1-q**(sum(part.arm_lengths(),[])[i])*t**(sum(part.leg_lengths(),[])[i]+1) return res +@cached_function +def Bmu( mu ): + r""" + Returns the bi-exponent generator for the cells of ``mu``. + + The weight in the bi-exponent generator is `t` raised the + `x`-coordinate of the cell, `q` raised to the `y` coordinate. + + INPUT: + + - ``mu`` -- a partition or a skew partition + + OUTPUT: + + - a polynomial in `q` and `t` + + EXAMPLES:: + + sage: Bmu(Partition([2,1])) + q + t + 1 + sage: Bmu(SkewPartition([[3,3],[2]])) + q^2*t + q^2 + q*t + t + """ + return sum(t**c[0]*q**c[1] for c in mu.cells()) + +@cached_function +def cmunu1(mu, nu): + r""" + Return the coefficient of `{\tilde H}_\nu` in `h_1^\perp {\tilde H}_\mu`. + + INPUT: + + - ``mu``, ``nu`` -- partitions with ``nu`` preceeds ``mu`` + + OUTPUT: + + - a rational polynomial in `q` and `t` + + EXAMPLES:: + + sage: cmunu1(Partition([2,1]),Partition([2])) + (-t^2 + q)/(q - t) + sage: cmunu1(Partition([2,1]),Partition([1,1])) + (-q^2 + t)/(-q + t) + sage: Sym = SymmetricFunctions(QQ['q','t'].fraction_field()) + sage: h = Sym.h() + sage: Ht = Sym.macdonald().Ht() + sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) == cmunu(Partition([3,2,1]),nu) for nu in Partition([3,2,1]).down_list()) + True + """ + # mu and nu should both be Partitions + c = sage.combinat.skew_partition.SkewPartition([mu,nu]).cells()[0] + A = prod((t**mu.leg_length(*s)-q**(mu.arm_length(*s)+1))/(t**nu.leg_length(*s)-q**(nu.arm_length(*s)+1)) for s in nu.cells() if s[0]==c[0]) + B = prod((q**mu.arm_length(*s)-t**(mu.leg_length(*s)+1))/(q**nu.arm_length(*s)-t**(nu.leg_length(*s)+1)) for s in nu.cells() if s[1]==c[1]) + return A*B + +@cached_function +def cmunu(mu, nu): + r""" + Return the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu`. + A theorem of F. Bergeron, A. Garsia and M. Haiman [BH2013]_ states + + .. MATH:: + + c_{\mu\nu} = \sum_{\alpha \leftarrow \nu} c_{\mu\alpha} c_{\alpha\nu} B_{\alpha/\nu}/B_{\mu/\nu} + + where `c_{\mu\nu}` is the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu`. + + INPUT: + + - ``mu``, ``nu`` -- partitions with ``nu`` contained in ``mu`` + + OUTPUT: + + - a rational polynomial in `q` and `t` + + EXAMPLES:: + + sage: cmunu(Partition([2,1]),Partition([1])) + q + t + 1 + sage: cmunu(Partition([2,2]),Partition([1,1])) + (-q^3 - q^2 + q*t + t)/(-q + t) + sage: Sym = SymmetricFunctions(QQ['q','t'].fraction_field()) + sage: h = Sym.h() + sage: Ht = Sym.macdonald().Ht() + sage: all(Ht[2,2].skew_by(h[r]).coefficient(nu) == cmunu(Partition([2,2]),nu) for r in range(1,5) for nu in Partitions(4-r)) + True + """ + if nu==[]: + return 1 + if not mu.contains(nu): + return 0 + if mu.size()==nu.size()+1: + return cmunu1(mu, nu) + return sum(cmunu(mu, al)*cmunu1(al, nu)*Bmu(sage.combinat.skew_partition.SkewPartition([al,nu])) for al in nu.up_list())/Bmu(sage.combinat.skew_partition.SkewPartition([mu,nu])) #Generic MacdonaldPolynomials class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): @@ -1173,6 +1273,8 @@ def __init__(self, macdonald): r""" The `Ht` basis is defined from the `H` basis by replacing `t \to 1/t` and multiplying by a normalizing power of `t`. + Here we define it by using a Pieri formula due to F. Bergeron, + A. Garsia and M. Haiman [BH2013]_. INPUT: @@ -1187,38 +1289,62 @@ def __init__(self, macdonald): sage: TestSuite(Ht).run(elements = [Ht.t*Ht[1,1]+Ht.q*Ht[2], Ht[1]+(Ht.q+Ht.t)*Ht[1,1]]) # long time (depends on previous) """ MacdonaldPolynomials_generic.__init__(self, macdonald) - self._self_to_s_cache = _ht_to_s_cache - self._s_to_self_cache = _s_to_ht_cache - self._J = macdonald.J() + self._self_to_m_cache = _ht_to_m_cache + self._m = self._sym.m() + category = sage.categories.all.ModulesWithBasis(self.base_ring()) + self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) + # in this case need to implement _self_to_m (similar to generic _self_to_s) and _m_cache - def _s_cache(self, n): + def _Lmunu(self, nu, mu ): r""" - Compute the change of basis and its inverse between the Macdonald - polynomials on the `Ht` basis and the Schur functions. - These computations are completed with coefficients in fraction - field of polynomials in `q` and `t` + Return the coefficient of `m_\nu` in `{\tilde H}_\mu`. + + The coefficient is a `(q,t)`-analogue of `n` choose `\nu`. + A theorem of F. Bergeron, A. Garsia and M. Haiman [BH2013]_ says that + + .. MATH:: + + L_{\mu\nu} = \sum_{\gamma} c_{\mu\gamma} L_{\overline{\nu}\gamma} + + where the sum is over partitions `\gamma \subseteq \mu` with + `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. INPUT: - - ``self`` -- a Macdonald `Ht` basis - - ``n`` -- a positive integer + - ``nu``, ``mu`` -- partitions of the same size + + OUTPUT: + + - a polynomial in `q` and `t` EXAMPLES:: - sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) - sage: Ht = Sym.macdonald().Ht() - sage: Ht._s_cache(2) - sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] - sage: l( Ht._s_to_self_cache[2] ) - [([1, 1], [([1, 1], 1/(-q + t)), ([2], (-1)/(-q + t))]), - ([2], [([1, 1], (-q)/(-q + t)), ([2], t/(-q + t))])] - sage: l( Ht._self_to_s_cache[2] ) - [([1, 1], [([1, 1], t), ([2], 1)]), ([2], [([1, 1], q), ([2], 1)])] + sage: Lmunu(Partition([3,1]),Partition([3,1])) + q^2 + q + t + 1 + sage: Lmunu(Partition([3,1]),Partition([2,2])) + q*t + q + t + 1 + sage: Lmunu(Partition([3,1]),Partition([2,1,1])) + t^2 + q + t + 1 + sage: Lmunu(Partition([2,2]),Partition([2,1,1])) + q*t + 2*t^2 + q + t + 1 """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, \ - self._s_to_self_cache, to_other_function = self._to_s) - - def _to_s(self, part): + if len(mu)==0: + if len(nu)==0: + return 1 + else: + return 0 + if (mu,nu) in self._self_to_m_cache: + return self._self_to_m_cache[(mu,nu)] + if len(nu)==1: + return 1 + if nu[-1]==1: + self._self_to_m_cache[(mu,nu)] = self._base(sum(cmunu1(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) for ga in mu.down_list())) + return self._self_to_m_cache[(mu,nu)] + self._self_to_m_cache[(mu,nu)] = self._base(sum( cmunu(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) + for ga in sage.combinat.partition.Partitions(nu.size()-nu[-1]) if mu.contains(ga))) + return self._self_to_m_cache[(mu,nu)] + + def _self_to_m(self, x): r""" Returns a function which gives the coefficient of a partition in the Schur expansion of ``self``(``part``). @@ -1247,16 +1373,9 @@ def _to_s(self, part): sage: [f22(part) for part in Partitions(4)] [1, q*t + q + t, q^2 + t^2, q^2*t + q*t^2 + q*t, q^2*t^2] """ - (q,t) = QQqt.gens() - Sym = self._sym - J = Sym.macdonald().J() - s = self._s - res = 0 - ve = part.weighted_size() - for p in sage.combinat.partition.Partitions(sum(part)): - res += t**ve*(J(part).scalar_t(s(p), t)).subs(t=1/t)*s(p) - f = lambda part2: res.coefficient(part2) - return f + return self._m._from_dict({ part2: sum(x.coefficient(mu)*self._Lmunu(part2, mu) + for mu in x.homogeneous_component(d).support()) + for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) class Element(MacdonaldPolynomials_generic.Element): def nabla(self, q=None, t=None, power=1): From 482dcacc93472a85ed27ca2757181d003f076687 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 11 Apr 2015 16:15:15 -0700 Subject: [PATCH 201/665] Doing some more cleanup and leaving comments. --- .../root_system/integrable_representations.py | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 051fcc3624a..e8106979a61 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -155,7 +155,7 @@ def __init__(self, Lam): self._smat = {} for i in self._index_set: for j in self._index_set: - self._smat[(i,j)] = -self._cartan_matrix[i][j] + self._smat[(i,j)] = -self._cartan_matrix[i,j] self._smat[(i,i)] += 1 self._shift = {} @@ -169,19 +169,15 @@ def __init__(self, Lam): Lam_rho = self._Lam + self._P.rho() self._den0 = Lam_rho.symmetric_form(Lam_rho) - def from_classical_root(h): - """ - Coerces a classical root into Q. - """ - return self._Q._from_dict(h._monomial_coefficients) - self._classical_roots = [from_classical_root(al) + # Coerce a classical root into Q + from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) + self._classical_roots = [from_cl_root(al) for al in self._Q.classical().roots()] - self._classical_positive_roots = [from_classical_root(al) + self._classical_positive_roots = [from_cl_root(al) for al in self._Q.classical().positive_roots()] - self._eps = {} - for i in self._index_set: - self._eps[i] = self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] + self._eps = {i: self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] + for i in self._index_set} def __repr__(self): """ @@ -202,8 +198,12 @@ def inner_qq(self, qelt1, qelt2): the parents are known, so checking would unnecessarily slow us down. """ - return sum(qelt1.monomial_coefficients().get(i,0)*qelt2.monomial_coefficients().get(j,0)* \ - self._cartan_matrix[i][j]/self._eps[i] for i in self._index_set for j in self._index_set) + mc1 = qelt1.monomial_coefficients() + mc2 = qelt2.monomial_coefficients() + zero = ZZ.zero() + return sum(mc1.get(i, zero) * mc2.get(j, zero) + * self._cartan_matrix[i,j] / self._eps[i] + for i in self._index_set for j in self._index_set) def inner_pq(self, pelt, qelt): """ @@ -217,7 +217,11 @@ def inner_pq(self, pelt, qelt): since in the application the parents are known, so checking would unnecessarily slow us down. """ - return sum(pelt.monomial_coefficients().get(i,0)*qelt.monomial_coefficients().get(i,0)/self._eps[i] for i in self._index_set) + mcp = pelt.monomial_coefficients() + mcq = qelt.monomial_coefficients() + zero = ZZ.zero() + return sum(mcp.get(i, zero) * mcq.get(i, zero) / self._eps[i] + for i in self._index_set) def to_weight(self, n): """ @@ -232,6 +236,8 @@ def to_weight(self, n): return self._Lam - self._P.sum(ZZ(val) * alpha[I[i]] for i,val in enumerate(n)) + # This recieves a significant number of calls. + # TODO: Try to reduce the number of such calls. def _from_weight_helper(self, mu): """ It is assumeed that ``mu`` is in the root lattice. @@ -239,12 +245,14 @@ def _from_weight_helper(self, mu): """ mu = self._P(mu) n0 = mu.monomial_coefficients().get('delta', 0) - mu0 = mu - n0*self._P.simple_root(0) - ret = [n0] + mu0 = mu - n0*self._P.simple_root(self._cartan_type.special_node()) + ret = [ZZ(n0)] + mc_mu0 = mu0.monomial_coefficients() + zero = ZZ.zero() for i in self._index_set_classical: - ret.append(sum(self._cminv[(i,j)]*mu0.monomial_coefficients().get(j,0) - for j in self._index_set_classical)) - return tuple(ZZ(i) for i in ret) + ret.append( ZZ.sum(self._cminv[(i,j)] * mc_mu0.get(j, zero) + for j in self._index_set_classical) ) + return tuple(ret) def from_weight(self, mu): """ @@ -257,9 +265,10 @@ def s(self, n, i): Implements the `i`-th simple reflection in the internal representation of weights by tuples. """ - ret = [n[j] for j in self._index_set] - ret[i] += self._Lam.monomial_coefficients().get(i,0) - ret[i] -= sum(n[j]*self._cartan_matrix[i][j] for j in self._index_set) + ret = list(n) # This makes a copy + ret[i] += self._Lam.monomial_coefficients().get(i, ZZ.zero()) + row = self._cartan_matrix[i] + ret[i] -= sum(n[j] * row[j] for j in self._index_set) return tuple(ret) def to_dominant(self, n): @@ -267,7 +276,7 @@ def to_dominant(self, n): return self._ddict[n] mc = self.to_weight(n).monomial_coefficients() for i in self._index_set: - if mc.get(i,0) < 0: + if mc.get(i, 0) < 0: m = self.s(n, i) v = self.to_dominant(m) self._ddict[n] = v @@ -285,9 +294,10 @@ def freudenthal_roots_imaginary(self, nu): return [u*delta for u in [1..kp]] """ l = self._from_weight_helper(nu) - kp = min(floor(l[i] / self._cartan_type.a()[i]) for i in self._index_set) + a = self._cartan_type.a() + kp = min(floor(l[i] / a[i]) for i in self._index_set) delta = self._Q.null_root() - return [u*delta for u in range(1,kp+1)] + return [u*delta for u in range(1, kp+1)] def freudenthal_roots_real(self, nu): r""" @@ -317,11 +327,12 @@ def freudenthal_roots(self, nu): ret.append(alpha) return ret + # TODO: (mostly to self) try to optimize starting here def _freudenthal_accum(self, nu, al): ret = 0 k = 1 - while min(self._from_weight_helper(self._Lam - nu - k*al)) >= 0: - mk = self.m(self.from_weight(nu + k*al)) + while all(val >= 0 for val in self._from_weight_helper(self._Lam - nu - k*al)): + mk = self.m( self.from_weight(nu + k*al) ) ip = self.inner_pq(nu + k*al, al) ret += 2*mk*ip k += 1 @@ -369,6 +380,8 @@ def m(self, n): print "m: error - failed to compute m%s"%n.__repr__() return ret + # FIXME: Make this generate itself without having needing to be called by string() + #@lazy_attribute def dominant_maximal(self): """ Return the finite set of dominant maximal weights. From 41f1cf2efd77ac28025babf868bf9273c8bd37fa Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 11 Apr 2015 23:07:03 -0400 Subject: [PATCH 202/665] Optimized _freudenthal_accum. --- .../root_system/integrable_representations.py | 60 ++++++++++++++----- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index e8106979a61..94e96d21001 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -129,6 +129,16 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 + + An example in type `C_2^{(1)}`:: + + sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[0]) + sage: v.strings() # long time + 2*Lambda[1] - delta: 1 4 15 44 122 304 721 1612 3469 7176 14414 28124 + Lambda[0] + Lambda[2] - delta: 1 5 18 55 149 372 872 1941 4141 8523 17005 33019 + 2*Lambda[0]: 1 2 9 26 77 194 477 1084 2387 5010 10227 20198 + 2*Lambda[2] - 2*delta: 2 7 26 72 194 467 1084 2367 5010 10191 20198 38907 """ def __init__(self, Lam): """ @@ -239,9 +249,17 @@ def to_weight(self, n): # This recieves a significant number of calls. # TODO: Try to reduce the number of such calls. def _from_weight_helper(self, mu): - """ - It is assumeed that ``mu`` is in the root lattice. - returns ``(n[0], n[1], ...)`` such that ``mu = \sum n[i]*alpha[i]`` + r""" + Return ``(n[0], n[1], ...)`` such that ``mu = \sum n[i]*alpha[i]``. + + INPUT: + + - ``mu`` -- an element in the root lattice + + .. TODO:: + + Implement this as a section map of the inverse of the + coercion from `Q \to P`. """ mu = self._P(mu) n0 = mu.monomial_coefficients().get('delta', 0) @@ -266,8 +284,8 @@ def s(self, n, i): representation of weights by tuples. """ ret = list(n) # This makes a copy - ret[i] += self._Lam.monomial_coefficients().get(i, ZZ.zero()) row = self._cartan_matrix[i] + ret[i] += self._Lam.monomial_coefficients().get(i, ZZ.zero()) ret[i] -= sum(n[j] * row[j] for j in self._index_set) return tuple(ret) @@ -285,8 +303,8 @@ def to_dominant(self, n): def freudenthal_roots_imaginary(self, nu): r""" - It is assumed that ``nu`` is in `Q`. Returns the set of imaginary roots - `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. + It is assumed that ``nu`` is in `Q`. Returns the set of imaginary + roots `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. Lambda = self._P.fundamental_weights() kp = min(ZZ(nu.symmetric_form(Lambda[i])) for i in self._index_set) @@ -327,15 +345,24 @@ def freudenthal_roots(self, nu): ret.append(alpha) return ret - # TODO: (mostly to self) try to optimize starting here def _freudenthal_accum(self, nu, al): + """ + Helper method for something with computing the Freudenthal formula. + """ ret = 0 - k = 1 - while all(val >= 0 for val in self._from_weight_helper(self._Lam - nu - k*al)): - mk = self.m( self.from_weight(nu + k*al) ) - ip = self.inner_pq(nu + k*al, al) + n = list(self._from_weight_helper(self._Lam - nu)) + ip = self.inner_pq(nu, al) + n_shift = self._from_weight_helper(al) + ip_shift = self.inner_qq(al, al) + + while all(val >= 0 for val in n): + # Change in data by adding ``al`` to our current weight + ip += ip_shift + for i,val in enumerate(n_shift): + n[i] -= val + # Compute the multiplicity + mk = self.m(tuple(n)) ret += 2*mk*ip - k += 1 return ret def m_freudenthal(self, n): @@ -348,12 +375,12 @@ def m_freudenthal(self, n): I = self._index_set al = self._Q._from_dict({I[i]: val for i,val in enumerate(n) if val}, remove_zeros=False) - den = 2*self.inner_pq(self._Lam+self._P.rho(), al) - self.inner_qq(al,al) + den = 2*self.inner_pq(self._Lam+self._P.rho(), al) - self.inner_qq(al, al) num = 0 for al in self.freudenthal_roots_real(self._Lam - mu): num += self._freudenthal_accum(mu, al) for al in self.freudenthal_roots_imaginary(self._Lam - mu): - num += self._classical_rank*self._freudenthal_accum(mu, al) + num += self._classical_rank * self._freudenthal_accum(mu, al) if den == 0 and num == 0: print "m_freudenthal","m: n=%s, num=den=0"%n.__repr__() try: @@ -410,10 +437,13 @@ def string(self, max_weight, depth=12): """ ret = [] delta = self._Q.null_root() + cur_weight = max_weight for k in range(depth): - ret.append(self.m( self.from_weight(max_weight - k*delta) )) + ret.append(self.m( self.from_weight(cur_weight) )) + cur_weight -= delta return ret + # FIXME: Return a dictionary def strings(self, depth=12): """ Return the set of dominant maximal weights of ``self``, together From ecc1b791f6a711ebec0799d185fa6617b6cdc752 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Apr 2015 00:38:44 -0400 Subject: [PATCH 203/665] Some more optimizations. --- .../root_system/integrable_representations.py | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 94e96d21001..4b7ec69bc34 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -14,10 +14,11 @@ #from sage.structure.parent import Parent from sage.categories.modules import Modules from sage.combinat.root_system.cartan_type import CartanType +from sage.combinat.root_system.root_space import RootSpace +from sage.combinat.root_system.weight_space import WeightSpace from sage.rings.all import ZZ, QQ from sage.misc.all import cached_method -from root_space import RootSpace -from weight_space import WeightSpace +from sage.matrix.matrix_space import MatrixSpace from sage.functions.other import floor # TODO: Make this a proper parent and implement actions @@ -155,12 +156,7 @@ def __init__(self, Lam): self._classical_rank = self._cartan_type.classical().rank() self._index_set = self._P.index_set() self._index_set_classical = self._cartan_type.classical().index_set() - - cmi = self._cartan_type.classical().cartan_matrix().inverse() - self._cminv = {} - for i in self._index_set_classical: - for j in self._index_set_classical: - self._cminv[(i,j)] = cmi[i-1][j-1] + self._cminv = self._cartan_type.classical().cartan_matrix().inverse() self._smat = {} for i in self._index_set: @@ -195,7 +191,7 @@ def __repr__(self): """ return "Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) - def inner_qq(self, qelt1, qelt2): + def _inner_qq(self, qelt1, qelt2): """ Symmetric form between two elements of the root lattice. @@ -215,7 +211,7 @@ def inner_qq(self, qelt1, qelt2): * self._cartan_matrix[i,j] / self._eps[i] for i in self._index_set for j in self._index_set) - def inner_pq(self, pelt, qelt): + def _inner_pq(self, pelt, qelt): """ Symmetric form between an element of the weight and root lattices @@ -230,8 +226,8 @@ def inner_pq(self, pelt, qelt): mcp = pelt.monomial_coefficients() mcq = qelt.monomial_coefficients() zero = ZZ.zero() - return sum(mcp.get(i, zero) * mcq.get(i, zero) / self._eps[i] - for i in self._index_set) + return sum(mcp.get(i, zero) * mcq[i] / self._eps[i] + for i in mcq) # Only need non-zero entries def to_weight(self, n): """ @@ -246,8 +242,6 @@ def to_weight(self, n): return self._Lam - self._P.sum(ZZ(val) * alpha[I[i]] for i,val in enumerate(n)) - # This recieves a significant number of calls. - # TODO: Try to reduce the number of such calls. def _from_weight_helper(self, mu): r""" Return ``(n[0], n[1], ...)`` such that ``mu = \sum n[i]*alpha[i]``. @@ -268,7 +262,8 @@ def _from_weight_helper(self, mu): mc_mu0 = mu0.monomial_coefficients() zero = ZZ.zero() for i in self._index_set_classical: - ret.append( ZZ.sum(self._cminv[(i,j)] * mc_mu0.get(j, zero) + # -1 for indexing + ret.append( ZZ.sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) for j in self._index_set_classical) ) return tuple(ret) @@ -284,15 +279,19 @@ def s(self, n, i): representation of weights by tuples. """ ret = list(n) # This makes a copy - row = self._cartan_matrix[i] - ret[i] += self._Lam.monomial_coefficients().get(i, ZZ.zero()) - ret[i] -= sum(n[j] * row[j] for j in self._index_set) + ret[i] += self._Lam._monomial_coefficients.get(i, ZZ.zero()) + ret[i] -= sum(val * self._cartan_matrix[i,j] for j,val in enumerate(n)) return tuple(ret) def to_dominant(self, n): - if self._ddict.has_key(n): + """ + Return a dominant weight of ``n`` obtained under reflections. + """ + if n in self._ddict: return self._ddict[n] + mc = self.to_weight(n).monomial_coefficients() + # Most weights are dense over the index set for i in self._index_set: if mc.get(i, 0) < 0: m = self.s(n, i) @@ -351,9 +350,9 @@ def _freudenthal_accum(self, nu, al): """ ret = 0 n = list(self._from_weight_helper(self._Lam - nu)) - ip = self.inner_pq(nu, al) + ip = self._inner_pq(nu, al) n_shift = self._from_weight_helper(al) - ip_shift = self.inner_qq(al, al) + ip_shift = self._inner_qq(al, al) while all(val >= 0 for val in n): # Change in data by adding ``al`` to our current weight @@ -375,7 +374,7 @@ def m_freudenthal(self, n): I = self._index_set al = self._Q._from_dict({I[i]: val for i,val in enumerate(n) if val}, remove_zeros=False) - den = 2*self.inner_pq(self._Lam+self._P.rho(), al) - self.inner_qq(al, al) + den = 2*self._inner_pq(self._Lam+self._P.rho(), al) - self._inner_qq(al, al) num = 0 for al in self.freudenthal_roots_real(self._Lam - mu): num += self._freudenthal_accum(mu, al) @@ -393,6 +392,10 @@ def m(self, n): Return the multiplicity. """ # TODO: Make this non-recursive by implementing our own stack + # The recursion follows: + # - m + # - m_freudenthal + # - _freudenthal_accum if self._mdict.has_key(n): return self._mdict[n] elif self._ddict.has_key(n): From 966ca5c317f3ea9b929d10be3f1f10a2ba2798bb Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 12 Apr 2015 01:20:51 -0400 Subject: [PATCH 204/665] The little things make all the difference. --- .../root_system/integrable_representations.py | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 4b7ec69bc34..c9e3311a30b 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -239,7 +239,7 @@ def to_weight(self, n): """ alpha = self._P.simple_roots() I = self._index_set - return self._Lam - self._P.sum(ZZ(val) * alpha[I[i]] + return self._Lam - self._P.sum(val * alpha[I[i]] for i,val in enumerate(n)) def _from_weight_helper(self, mu): @@ -258,13 +258,13 @@ def _from_weight_helper(self, mu): mu = self._P(mu) n0 = mu.monomial_coefficients().get('delta', 0) mu0 = mu - n0*self._P.simple_root(self._cartan_type.special_node()) - ret = [ZZ(n0)] + ret = [n0] # This should be in ZZ because it is in the weight lattice mc_mu0 = mu0.monomial_coefficients() zero = ZZ.zero() for i in self._index_set_classical: # -1 for indexing - ret.append( ZZ.sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) - for j in self._index_set_classical) ) + ret.append( ZZ(sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) + for j in self._index_set_classical)) ) return tuple(ret) def from_weight(self, mu): @@ -290,15 +290,37 @@ def to_dominant(self, n): if n in self._ddict: return self._ddict[n] - mc = self.to_weight(n).monomial_coefficients() - # Most weights are dense over the index set - for i in self._index_set: - if mc.get(i, 0) < 0: - m = self.s(n, i) - v = self.to_dominant(m) - self._ddict[n] = v - return v - return n + path = [n] + alpha = self._P.simple_roots() + next = True + cur_wt = self.to_weight(n) + + while next: + if path[-1] in self._ddict: + path.append( self._ddict[path[-1]] ) + break + + next = False + mc = cur_wt.monomial_coefficients() + # Most weights are dense over the index set + for i in self._index_set: + if mc.get(i, 0) < 0: + m = self.s(path[-1], i) + if m in self._ddict: + path.append(self._ddict[m]) + else: + cur_wt -= (m[i] - path[-1][i]) * alpha[i] + path.append(m) + next = True + break + + # We don't want any dominat weight to refer to itself in self._ddict + # as this leads to an infinite loop with self.m() when the dominant + # weight does not have a known multiplicity. + v = path.pop() + for m in path: + self._ddict[m] = v + return v def freudenthal_roots_imaginary(self, nu): r""" From a58c2f9bae6bc12172caf60a17bf5cb55b1fba9a Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 12 Apr 2015 10:40:15 +0200 Subject: [PATCH 205/665] trac #17464: Remove bliss from module_list.py --- src/module_list.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 15f7f5e1e0b..86ff0eabcce 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -2095,13 +2095,6 @@ def uname_specific(name, value, alternative): include_dirs = [SAGE_INC + '/flint'], depends = flint_depends) ]) -if is_package_installed('bliss'): - ext_modules.append( - Extension("sage.graphs.bliss", - ["sage/graphs/bliss.pyx"], - language = "c++", - libraries= ["bliss"]) - ) # Only include darwin_utilities on OS_X >= 10.5 UNAME = os.uname() From e9639c2f1d3779dde344b7bdae3b00f07a14dced Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 12 Apr 2015 10:43:10 +0200 Subject: [PATCH 206/665] trac #17464: Add bliss to module_list.py --- src/module_list.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/module_list.py b/src/module_list.py index bd2bb285bba..2a0734bb8fb 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -421,6 +421,12 @@ def uname_specific(name, value, alternative): language = "c++", package = 'mcqd'), + OptionalExtension("sage.graphs.bliss", + ["sage/graphs/bliss.pyx"], + language = "c++", + libraries = ['bliss'], + package = 'bliss'), + OptionalExtension('sage.graphs.modular_decomposition', sources = ['sage/graphs/modular_decomposition.pyx'], libraries = ['modulardecomposition'], From 44d8462ffc5bff9086c5f408542100b5580c031d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 12 Apr 2015 12:44:41 +0200 Subject: [PATCH 207/665] trac #17164: Broken doctest --- src/sage/graphs/bliss.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 78db48a0b19..114da31612b 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -279,10 +279,10 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): if return_graph: if G.is_directed(): from sage.graphs.graph import DiGraph - G = DiGraph(edges) + G = DiGraph(edges,loops=G.allows_loops(),multiedges=G.allows_multiple_edges()) else: from sage.graphs.graph import Graph - G = Graph(edges) + G = Graph(edges,loops=G.allows_loops(),multiedges=G.allows_multiple_edges()) G.add_vertices(vert2int.values()) return (G, vert2int) if certify else G From c272b7f4300d1f6c6f61322e29fc6910d8b66a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Sun, 12 Apr 2015 15:49:34 +0200 Subject: [PATCH 208/665] Trac #16352: Fixed referee comment --- src/sage/groups/conjugacy_classes.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index 7cf8d55ad0a..3553af8e8a0 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -177,19 +177,29 @@ def __iter__(self): sage: a = matrix(ZZ,2,[1,1,0,1]) sage: b = matrix(ZZ,2,[1,0,1,1]) sage: G = MatrixGroup([a,b]) # takes 1s - sage: g = G(a) - sage: C = ConjugacyClass(G, g) + sage: a = G(a) + sage: C = ConjugacyClass(G, a) sage: it = iter(C) sage: [next(it) for _ in range(5)] [ - [1 1] [ 0 1] [-1 1] [-1 4] [-5 9] - [0 1], [-1 2], [-4 3], [-1 3], [-4 7] + [1 1] [ 2 1] [ 0 1] [ 3 1] [ 3 4] + [0 1], [-1 0], [-1 2], [-4 -1], [-1 -1] ] + We check that two matrices are in C:: + + sage: b = G(b) + sage: m1 = b * a * ~b + sage: m2 = ~b * a * b + sage: any(x == m1 for x in C) + True + sage: any(x == m2 for x in C) + True + """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet g = self._representative - gens = self._parent.gens() + gens = self._parent.monoid_generators() R = RecursivelyEnumeratedSet([g], lambda y: [c*y*c**-1 for c in gens], structure=None) From f49d09d82837eb104a2258e588617358f16599cf Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 12 Apr 2015 10:47:19 -0400 Subject: [PATCH 209/665] add coercion from m to Ht basis, add specialization of q and t --- src/sage/combinat/sf/macdonald.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index b4c27e14d89..15389be9bb9 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -639,6 +639,7 @@ def Bmu( mu ): sage: Bmu(SkewPartition([[3,3],[2]])) q^2*t + q^2 + q*t + t """ + q,t = QQqt.gens() return sum(t**c[0]*q**c[1] for c in mu.cells()) @cached_function @@ -666,7 +667,7 @@ def cmunu1(mu, nu): sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) == cmunu(Partition([3,2,1]),nu) for nu in Partition([3,2,1]).down_list()) True """ - # mu and nu should both be Partitions + q,t = QQqt.gens() c = sage.combinat.skew_partition.SkewPartition([mu,nu]).cells()[0] A = prod((t**mu.leg_length(*s)-q**(mu.arm_length(*s)+1))/(t**nu.leg_length(*s)-q**(nu.arm_length(*s)+1)) for s in nu.cells() if s[0]==c[0]) B = prod((q**mu.arm_length(*s)-t**(mu.leg_length(*s)+1))/(q**nu.arm_length(*s)-t**(nu.leg_length(*s)+1)) for s in nu.cells() if s[1]==c[1]) @@ -1293,6 +1294,7 @@ def __init__(self, macdonald): self._m = self._sym.m() category = sage.categories.all.ModulesWithBasis(self.base_ring()) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) + self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) # in this case need to implement _self_to_m (similar to generic _self_to_s) and _m_cache def _Lmunu(self, nu, mu ): @@ -1319,6 +1321,7 @@ def _Lmunu(self, nu, mu ): EXAMPLES:: + sage: Lmunu = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().Ht()._Lmunu sage: Lmunu(Partition([3,1]),Partition([3,1])) q^2 + q + t + 1 sage: Lmunu(Partition([3,1]),Partition([2,2])) @@ -1338,9 +1341,9 @@ def _Lmunu(self, nu, mu ): if len(nu)==1: return 1 if nu[-1]==1: - self._self_to_m_cache[(mu,nu)] = self._base(sum(cmunu1(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) for ga in mu.down_list())) + self._self_to_m_cache[(mu,nu)] = QQqt(sum(cmunu1(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) for ga in mu.down_list())) return self._self_to_m_cache[(mu,nu)] - self._self_to_m_cache[(mu,nu)] = self._base(sum( cmunu(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) + self._self_to_m_cache[(mu,nu)] = QQqt(sum( cmunu(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) for ga in sage.combinat.partition.Partitions(nu.size()-nu[-1]) if mu.contains(ga))) return self._self_to_m_cache[(mu,nu)] @@ -1373,9 +1376,22 @@ def _self_to_m(self, x): sage: [f22(part) for part in Partitions(4)] [1, q*t + q + t, q^2 + t^2, q^2*t + q*t^2 + q*t, q^2*t^2] """ - return self._m._from_dict({ part2: sum(x.coefficient(mu)*self._Lmunu(part2, mu) - for mu in x.homogeneous_component(d).support()) - for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) + return self._m._from_dict({ part2: + self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=self.t) + for mu in x.homogeneous_component(d).support())) + for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) + + def _m_to_self( self, f ): + r""" + """ + g = f(self._m([1])*(self.t-1)) + out = {} + while not g.is_zero(): + sprt = g.support() + Htmu = self._self_to_m(self(sprt[-1]))(self._m([1])*(self.t-1)) + out[sprt[-1]] = g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1]) + g -= out[sprt[-1]]*Htmu + return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): def nabla(self, q=None, t=None, power=1): From 0832bbc90db342d49171de443e1de1bed839e02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Sun, 12 Apr 2015 18:14:05 +0200 Subject: [PATCH 210/665] Trac #16352: removed a TODO in backtrac.py --- src/sage/combinat/backtrack.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 169fa31d59f..47e32e35c10 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -41,11 +41,6 @@ ``sage/sets/recursively_enumerated_set.pyx`` into a class named ``RecursivelyEnumeratedSet_forest`` in a later ticket. -- ``TransitiveIdeal`` and ``TransitiveIealGraded`` are used in the code of - ``sage/combinat``, ``sage/categories`` and ``sage/groups`` at least. - These should be updated to use ``RecursivelyEnumeratedSet`` in a later - ticket for speed improvements. - - Once the deprecation has been there for enough time: delete ``TransitiveIdeal`` and ``TransitiveIealGraded``. From 9d708203dd3236f3c192faab6b573799fa5c1c32 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 12 Apr 2015 18:45:07 +0200 Subject: [PATCH 211/665] trac #17464: Broken doc --- src/sage/graphs/generic_graph.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b539918b868..7c5af054d6b 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17329,8 +17329,7 @@ def coarsest_equitable_refinement(self, partition, sparse=True): def automorphism_group(self, partition=None, verbosity=0, edge_labels=False, order=False, return_group=True, orbits=False, algorithm=None): - """ - Returns the largest subgroup of the automorphism group of the + """Returns the largest subgroup of the automorphism group of the (di)graph whose orbit partition is finer than the partition given. If no partition is given, the unit partition is used and the entire automorphism group is given. @@ -17354,10 +17353,10 @@ def automorphism_group(self, partition=None, verbosity=0, on the vertices of the graph - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is - computed using the optional package bliss - (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). Setting it to - "sage" uses Sage's implementation. If set to ``None`` (default), - bliss is used when available. + computed using the optional package bliss + (http://www.tcs.tkk.fi/Software/bliss/index.html). Setting it to + "sage" uses Sage's implementation. If set to ``None`` (default), bliss + is used when available. .. WARNING:: @@ -17785,8 +17784,7 @@ def is_hamiltonian(self): return False def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, algorithm=None): - """ - Tests for isomorphism between self and other. + """Tests for isomorphism between self and other. INPUT: @@ -17797,9 +17795,10 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, al - ``edge_labels`` - default False, otherwise allows only permutations respecting edge labels. - - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group - is computed using bliss (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). - Note that bliss package must be installed. + - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is + computed using bliss + (http://www.tcs.tkk.fi/Software/bliss/index.html). Note that bliss + package must be installed. EXAMPLES: Graphs:: @@ -18108,10 +18107,10 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, only permutations respecting edge labels. - ``algorithm`` - If ``algorithm = "bliss"`` the automorphism group is - computed using the optional package bliss - (`http://www.tcs.tkk.fi/Software/bliss/index.html`_). Setting it to - "sage" uses Sage's implementation. If set to ``None`` (default), - bliss is used when available. + computed using the optional package bliss + (http://www.tcs.tkk.fi/Software/bliss/index.html). Setting it to + "sage" uses Sage's implementation. If set to ``None`` (default), bliss + is used when available. .. NOTE:: From 42184c41b49d4d5e7449d3d3a0eb76dcf16e281a Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 12 Apr 2015 14:23:29 -0400 Subject: [PATCH 212/665] implemented H basis using Ht basis, began working on documentation --- src/sage/combinat/sf/macdonald.py | 106 +++++++++--------------------- 1 file changed, 32 insertions(+), 74 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 15389be9bb9..b39087934d2 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -29,9 +29,9 @@ Macdonald Polynomials, IRMN no. 18 (1998). :arXiv:`math/9808050`. -.. [BH2013] Tableaux Formulas for Macdonald Polynomials, Special edition - in honour of Christophe Reutenauer 60 birthday, International Journal - of Algebra and Computation, Volume 23, Issue 4, (2013), pp. 833-852. +.. [BH2013] F. Bergeron, M. Haiman, Tableaux Formulas for Macdonald Polynomials, + Special edition in honor of Christophe Reutenauer 60 birthday, International + Journal of Algebra and Computation, Volume 23, Issue 4, (2013), pp. 833-852. """ #***************************************************************************** @@ -1178,9 +1178,11 @@ class Element(MacdonaldPolynomials_generic.Element): class MacdonaldPolynomials_h(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" - The `H` basis is expanded in the Schur basis by extracting the - `q,t`-Kostka coefficient through the `t`-scalar product of `J_{\mu}` - and `s_{\lambda}`. + The `H` basis is defined as `H_\mu = \sum_{\lambda} K_{\lambda\mu}(q,t) s_\lambda` + where `K_{\lambda\mu}(q,t)` are the Macdonald Kostka coefficients. + + In this implementation, it is calculated by using the Macdonald `Ht` basis and + substituting `t \rightarrow 1/t` and multiplying by `t^{n(\mu)}`. INPUT: @@ -1194,77 +1196,32 @@ def __init__(self, macdonald): sage: TestSuite(H).run(skip=["_test_associativity","_test_distributivity","_test_prod"]) sage: TestSuite(H).run(elements = [H.t*H[1,1]+H.q*H[2], H[1]+(H.q+H.t)*H[1,1]]) # long time (26s on sage.math, 2012) """ - self._self_to_s_cache = _h_to_s_cache - self._s_to_self_cache = _s_to_h_cache MacdonaldPolynomials_generic.__init__(self, macdonald) - self._Ht = macdonald.Ht() - + self._m = self._sym.m() + self._Lmunu = macdonald.Ht()._Lmunu + category = sage.categories.all.ModulesWithBasis(self.base_ring()) + self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) + self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) - def _s_cache(self, n): + def _self_to_m( self, x ): r""" - Compute the change of basis and its inverse between the Macdonald - polynomials on the `H` basis and the Schur functions. - these computations are completed with coefficients in fraction - field of polynomials in `q` and `t` - - INPUT: - - - ``self`` -- a Macdonald `H` basis - - ``n`` -- a non-negative integer - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) - sage: H = Sym.macdonald().H() - sage: H._s_cache(2) - sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] - sage: l( H._s_to_self_cache[2] ) - [([1, 1], [([1, 1], 1/(-q*t + 1)), ([2], (-t)/(-q*t + 1))]), - ([2], [([1, 1], (-q)/(-q*t + 1)), ([2], 1/(-q*t + 1))])] - sage: l( H._self_to_s_cache[2] ) - [([1, 1], [([1, 1], 1), ([2], t)]), ([2], [([1, 1], q), ([2], 1)])] """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, \ - self._s_to_self_cache, to_other_function = self._to_s) + return self._m._from_dict({ part2: + self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=1/self.t)*self.t**mu.weighted_size() + for mu in x.homogeneous_component(d).support())) + for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) - def _to_s(self, part): + def _m_to_self( self, f ): r""" - Returns a function which gives the coefficient of a partition in - the Schur expansion of self(part). - these computations are completed with coefficients in fraction - field of polynomials in `q` and `t` - - INPUT: - - - ``self`` -- a Macdonald `H` basis - - ``part`` -- a partition - - OUTPUT: - - - returns a function which returns the coefficients of the expansion of `H` - in the Schur basis - - EXAMPLES:: - - sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) - sage: H = Sym.macdonald().H() - sage: f21 = H._to_s(Partition([2,1])) - sage: [f21(part) for part in Partitions(3)] - [t, q*t + 1, q] - sage: Sym.schur()( H[2,1] ) - q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3] - sage: f22 = H._to_s(Partition([2,2])) - sage: [f22(part) for part in Partitions(4)] - [t^2, q*t^2 + q*t + t, q^2*t^2 + 1, q^2*t + q*t + q, q^2] """ - (q,t) = QQqt.gens() - J = self._macdonald.J() - s = self._s - res = 0 - for p in sage.combinat.partition.Partitions(sum(part)): - res += (J(part).scalar_t(s(p), t))*s(p) - f = lambda part2: res.coefficient(part2) - return f + g = f(self._m([1])*(1-self.t)) + out = {} + while not g.is_zero(): + sprt = g.support() + Hmu = self._self_to_m(self(sprt[-1]))(self._m([1])*(1-self.t)) + out[sprt[-1]] = g.coefficient(sprt[-1])/Hmu.coefficient(sprt[-1]) + g -= out[sprt[-1]]*Hmu + return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): pass @@ -1272,9 +1229,11 @@ class Element(MacdonaldPolynomials_generic.Element): class MacdonaldPolynomials_ht(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" - The `Ht` basis is defined from the `H` basis by replacing `t \to 1/t` - and multiplying by a normalizing power of `t`. - Here we define it by using a Pieri formula due to F. Bergeron, + The `Ht` basis is defined as `{\tilde H}_\mu = t^{n(\mu)} \sum_{\lambda} + K_{\lambda\mu}(q,t^{-1}) s_\lambda` where `K_{\lambda\mu}(q,t)` are the + Macdonald `(q,t)`-Kostka coefficients and `n(\mu) = \sum_{i} (i-1) \mu_i`. + + It is implemented here by using a Pieri formula due to F. Bergeron, A. Garsia and M. Haiman [BH2013]_. INPUT: @@ -1295,7 +1254,6 @@ def __init__(self, macdonald): category = sage.categories.all.ModulesWithBasis(self.base_ring()) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) - # in this case need to implement _self_to_m (similar to generic _self_to_s) and _m_cache def _Lmunu(self, nu, mu ): r""" From 4a2d08640f997a34093147bfb480ebe5c08374bd Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 12 Apr 2015 16:54:20 -0400 Subject: [PATCH 213/665] added documentation and examples --- src/sage/combinat/sf/macdonald.py | 128 ++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index b39087934d2..810e403b3d7 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1195,6 +1195,7 @@ def __init__(self, macdonald): sage: H = Sym.macdonald().H() sage: TestSuite(H).run(skip=["_test_associativity","_test_distributivity","_test_prod"]) sage: TestSuite(H).run(elements = [H.t*H[1,1]+H.q*H[2], H[1]+(H.q+H.t)*H[1,1]]) # long time (26s on sage.math, 2012) + """ MacdonaldPolynomials_generic.__init__(self, macdonald) self._m = self._sym.m() @@ -1205,6 +1206,32 @@ def __init__(self, macdonald): def _self_to_m( self, x ): r""" + Takes an element of the ``H`` basis and returns the expansion in the + monomial basis. + + INPUT: + + - ``x`` -- an element of ``H`` basis + + OUTPUT: + + - an element of the monomial basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) + sage: H = Sym.macdonald().H() + sage: m = Sym.m() + sage: m(H[2,1]) + (2*q*t+q+t+2)*m[1, 1, 1] + (q*t+t+1)*m[2, 1] + t*m[3] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: H = Sym.macdonald(q=x,t=1/x).H() + sage: m = Sym.m() + sage: m(H[2,1]) + ((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3] + """ return self._m._from_dict({ part2: self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=1/self.t)*self.t**mu.weighted_size() @@ -1213,6 +1240,39 @@ def _self_to_m( self, x ): def _m_to_self( self, f ): r""" + Convert an element ``f`` from the monomial basis to the ``H`` basis. + + This calculation is performed by using the fact that `{\tilde H}_\mu[X(t-1)]` + is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading + coefficient of the expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to + the leading coefficient of `c_\mu^{-1} f[X(t-1)]`. + + INPUT: + + - ``f`` -- an element of the monomial basis + + OUTPUT: + + - an element of the ``H`` basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) + sage: H = Sym.macdonald().H() + sage: m = Sym.m() + sage: H(m[1,1]) + -(1/(q*t-1))*McdH[1, 1] + (t/(q*t-1))*McdH[2] + sage: (q,t) = Sym.base_ring().gens() + sage: H((2*q*t+q+t+2)*m[1, 1, 1] + (q*t+t+1)*m[2, 1] + t*m[3]) + McdH[2, 1] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: H = Sym.macdonald(q=x,t=1/x).H() + sage: m = Sym.m() + sage: H(((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3]) + McdH[2, 1] + """ g = f(self._m([1])*(1-self.t)) out = {} @@ -1247,6 +1307,7 @@ def __init__(self, macdonald): sage: Ht = Sym.macdonald().Ht() sage: TestSuite(Ht).run(skip=["_test_associativity","_test_distributivity","_test_prod"]) # long time (26s on sage.math, 2012) sage: TestSuite(Ht).run(elements = [Ht.t*Ht[1,1]+Ht.q*Ht[2], Ht[1]+(Ht.q+Ht.t)*Ht[1,1]]) # long time (depends on previous) + """ MacdonaldPolynomials_generic.__init__(self, macdonald) self._self_to_m_cache = _ht_to_m_cache @@ -1288,6 +1349,7 @@ def _Lmunu(self, nu, mu ): t^2 + q + t + 1 sage: Lmunu(Partition([2,2]),Partition([2,1,1])) q*t + 2*t^2 + q + t + 1 + """ if len(mu)==0: if len(nu)==0: @@ -1307,32 +1369,32 @@ def _Lmunu(self, nu, mu ): def _self_to_m(self, x): r""" - Returns a function which gives the coefficient of a partition in - the Schur expansion of ``self``(``part``). - These computations are completed with coefficients in fraction - field of polynomials in `q` and `t` + Takes an element of the ``Ht`` basis and returns the expansion in the + monomial basis. INPUT: - - ``self`` -- a Macdonald `Ht` basis - - ``part`` -- a partition + - ``x`` -- an element of ``Ht`` basis OUTPUT: - - returns a function which accepts a partition ``part2`` and - this function returns the coefficient of the Schur function - indexed by ``part2`` in ``Ht(part)`` + - an element of the monomial basis EXAMPLES:: sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) sage: Ht = Sym.macdonald().Ht() - sage: f21 = Ht._to_s(Partition([2,1])) - sage: [f21(part) for part in Partitions(3)] - [1, q + t, q*t] - sage: f22 = Ht._to_s(Partition([2,2])) - sage: [f22(part) for part in Partitions(4)] - [1, q*t + q + t, q^2 + t^2, q^2*t + q*t^2 + q*t, q^2*t^2] + sage: m = Sym.m() + sage: m(Ht[2,1]) + (q*t+2*q+2*t+1)*m[1, 1, 1] + (q+t+1)*m[2, 1] + m[3] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: Ht = Sym.macdonald(q=x,t=1/x).Ht() + sage: m = Sym.m() + sage: m(Ht[2,1]) + ((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3] + """ return self._m._from_dict({ part2: self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=self.t) @@ -1341,13 +1403,46 @@ def _self_to_m(self, x): def _m_to_self( self, f ): r""" + Convert an element ``f`` from the monomial basis to the ``Ht`` basis. + + This calculation is performed by using the fact that `{\tilde H}_\mu[X(t-1)]` + is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading + coefficient of the expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to + the leading coefficient of `c_\mu^{-1} f[X(t-1)]`. + + INPUT: + + - ``f`` -- an element of the monomial basis + + OUTPUT: + + - an element of the ``Ht`` basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) + sage: Ht = Sym.macdonald().Ht() + sage: m = Sym.m() + sage: Ht(m[1,1]) + (1/(-q+t))*McdHt[1, 1] - (1/(-q+t))*McdHt[2] + sage: (q,t) = Sym.base_ring().gens() + sage: Ht((q*t+2*q+2*t+1)*m[1, 1, 1] + (q+t+1)*m[2, 1] + m[3]) + McdHt[2, 1] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: Ht = Sym.macdonald(q=x,t=1/x).Ht() + sage: m = Sym.m() + sage: Ht(((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3]) + McdHt[2, 1] + """ g = f(self._m([1])*(self.t-1)) out = {} while not g.is_zero(): sprt = g.support() Htmu = self._self_to_m(self(sprt[-1]))(self._m([1])*(self.t-1)) - out[sprt[-1]] = g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1]) + out[sprt[-1]] = self._base(g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1])) g -= out[sprt[-1]]*Htmu return self._from_dict(out) @@ -1400,6 +1495,7 @@ def nabla(self, q=None, t=None, power=1): sage: a = sum(Ht(p) for p in Partitions(3)) sage: s(a.nabla()) (t^6+9*t^2+729)*s[1, 1, 1] + (t^5+t^4+3*t^2+9*t+324)*s[2, 1] + (t^3+3*t+27)*s[3] + """ P = self.parent() Ht = P._macdonald.Ht() From e1dbb22a97d046ede39c4220fa2d8dfa10550848 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 12 Apr 2015 17:34:52 -0400 Subject: [PATCH 214/665] updates and corrections to documentation --- src/sage/combinat/sf/macdonald.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 810e403b3d7..7cf7ec8fe4d 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1242,10 +1242,10 @@ def _m_to_self( self, f ): r""" Convert an element ``f`` from the monomial basis to the ``H`` basis. - This calculation is performed by using the fact that `{\tilde H}_\mu[X(t-1)]` + This calculation is performed by using the fact that `H_\mu[X(1-t)]` is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading - coefficient of the expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to - the leading coefficient of `c_\mu^{-1} f[X(t-1)]`. + coefficient of the expansion of ``f`` in the `H_\mu` basis is equal to + the leading coefficient of `c_\mu^{-1} f[X(1-t)]`. INPUT: @@ -1320,15 +1320,18 @@ def _Lmunu(self, nu, mu ): r""" Return the coefficient of `m_\nu` in `{\tilde H}_\mu`. - The coefficient is a `(q,t)`-analogue of `n` choose `\nu`. - A theorem of F. Bergeron, A. Garsia and M. Haiman [BH2013]_ says that + The coefficient is a `(q,t)`-analogue of `n` choose `\nu`. Let `c_{\mu\gamma}` + be the coefficient of `{\tilde H}_\gamma` in `h_r^\perp {\tilde H}_\mu`. The + coefficient of `m_\nu` in `{\tilde H}_\mu` is .. MATH:: - L_{\mu\nu} = \sum_{\gamma} c_{\mu\gamma} L_{\overline{\nu}\gamma} + L_{\mu\nu} = \sum_{\gamma} c_{\mu\gamma} L_{\gamma\overline{\nu}} where the sum is over partitions `\gamma \subseteq \mu` with - `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. + `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. There is a recursive + formula for `c_{\mu\gamma}` which is due to F. Bergeron, A. Garsia, and M. + Haiman [BH2013]_. INPUT: From 216e29c729ed2405d73a0d53e2a7d38da9a34ba8 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Mon, 13 Apr 2015 09:31:44 +0200 Subject: [PATCH 215/665] 18155: changed chksum for tarball made with make dist --- build/pkgs/pynac/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/pynac/checksums.ini b/build/pkgs/pynac/checksums.ini index d38bc102a67..76267b95744 100644 --- a/build/pkgs/pynac/checksums.ini +++ b/build/pkgs/pynac/checksums.ini @@ -1,4 +1,4 @@ tarball=pynac-VERSION.tar.bz2 -sha1=76fea7a56a14d52eb2d14aaf11e21598bd68a8b4 -md5=1bbb82164082440cf87bb83d28b056b3 -cksum=3562766241 +sha1=cc294fc603232c651c2a43eb5536cf947ace9680 +md5=beb6202f614234b545a193fc23b10667 +cksum=3010177260 From 839c49fbf7ae9a8917fda4ed326e7f58729a02b4 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Mon, 13 Apr 2015 10:20:40 +0200 Subject: [PATCH 216/665] 18155: file change --- build/pkgs/pynac/checksums.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pynac/checksums.ini b/build/pkgs/pynac/checksums.ini index 76267b95744..b4f91b657b6 100644 --- a/build/pkgs/pynac/checksums.ini +++ b/build/pkgs/pynac/checksums.ini @@ -1,4 +1,4 @@ -tarball=pynac-VERSION.tar.bz2 -sha1=cc294fc603232c651c2a43eb5536cf947ace9680 -md5=beb6202f614234b545a193fc23b10667 -cksum=3010177260 +tarball=pynac-VERSION.tar.gz +sha1=56ac44ec35059c427380f19a30a6d280dd2a3841 +md5=52f77820bfe0cb4cda7d86d9e486bccf +cksum=495493650 From ced7bfcc760e2fb362b2a382a22a94e02f996f9b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 13 Apr 2015 11:10:37 +0200 Subject: [PATCH 217/665] Trac 18157: fix garbage collected objects in doctest --- src/sage/structure/coerce.pyx | 76 +++++++++++++++++---------- src/sage/structure/coerce_actions.pyx | 58 +++++++++++++------- 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6756c9c1b3f..3c91ee15d44 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -239,7 +239,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: from sage.structure.coerce import CoercionModel_cache_maps sage: cm = CoercionModel_cache_maps(4, .95) - sage: A = cm.get_action(ZZ, NumberField(x^2-2, 'a'), operator.mul) + sage: K = NumberField(x^2-2, 'a') + sage: A = cm.get_action(ZZ, K, operator.mul) sage: f, g = cm.coercion_maps(QQ, int) sage: f, g = cm.coercion_maps(ZZ, int) @@ -476,7 +477,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): Result lives in Rational Field Rational Field - sage: cm.explain(ZZ['x'], QQ) + sage: R = ZZ['x'] + sage: cm.explain(R, QQ) Action discovered. Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring Result lives in Univariate Polynomial Ring in x over Rational Field @@ -502,10 +504,11 @@ cdef class CoercionModel_cache_maps(CoercionModel): Sometimes with non-sage types there is not enough information to deduce what will actually happen:: - sage: cm.explain(RealField(100), float, operator.add) + sage: R100 = RealField(100) + sage: cm.explain(R100, float, operator.add) Right operand is numeric, will attempt coercion in both directions. Unknown result parent. - sage: parent(RealField(100)(1) + float(1)) + sage: parent(R100(1) + float(1)) sage: cm.explain(QQ, float, operator.add) Right operand is numeric, will attempt coercion in both directions. @@ -521,7 +524,9 @@ cdef class CoercionModel_cache_maps(CoercionModel): Result lives in Rational Field Rational Field - sage: cm.explain(ZZ['x'], QQ['x'], operator.div) + sage: ZZx = ZZ['x'] + sage: QQx = QQ['x'] + sage: cm.explain(ZZx, QQx, operator.div) Coercion on left operand via Ring morphism: From: Univariate Polynomial Ring in x over Integer Ring @@ -543,7 +548,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): Result lives in Rational Field Rational Field - sage: cm.explain(ZZ['x'], ZZ, operator.div) + sage: cm.explain(ZZx, ZZ, operator.div) Action discovered. Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring with precomposition on right by Natural morphism: @@ -583,7 +588,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): EXAMPLES:: sage: cm = sage.structure.element.get_coercion_model() - sage: steps, res = cm.analyse(GF(7), ZZ) + sage: GF7 = GF(7) + sage: steps, res = cm.analyse(GF7, ZZ) sage: print steps ['Coercion on right operand via', Natural morphism: From: Integer Ring @@ -691,23 +697,29 @@ cdef class CoercionModel_cache_maps(CoercionModel): Rational Field sage: cm.common_parent(ZZ, QQ, RR) Real Field with 53 bits of precision - sage: cm.common_parent(ZZ[['T']], QQ['T'], RDF) + sage: ZZT = ZZ[['T']] + sage: QQT = QQ['T'] + sage: cm.common_parent(ZZT, QQT, RDF) Power Series Ring in T over Real Double Field sage: cm.common_parent(4r, 5r) sage: cm.common_parent(int, float, ZZ) - sage: cm.common_parent(*[RealField(prec) for prec in [10,20..100]]) + sage: real_fields = [RealField(prec) for prec in [10,20..100]] + sage: cm.common_parent(*real_fields) Real Field with 10 bits of precision There are some cases where the ordering does matter, but if a parent can be found it is always the same:: - sage: cm.common_parent(QQ['x,y'], QQ['y,z']) == cm.common_parent(QQ['y,z'], QQ['x,y']) + sage: QQxy = QQ['x,y'] + sage: QQyz = QQ['y,z'] + sage: cm.common_parent(QQxy, QQyz) == cm.common_parent(QQyz, QQxy) True - sage: cm.common_parent(QQ['x,y'], QQ['y,z'], QQ['z,t']) + sage: QQzt = QQ['z,t'] + sage: cm.common_parent(QQxy, QQyz, QQzt) Multivariate Polynomial Ring in x, y, z, t over Rational Field - sage: cm.common_parent(QQ['x,y'], QQ['z,t'], QQ['y,z']) + sage: cm.common_parent(QQxy, QQzt, QQyz) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Multivariate Polynomial Ring in x, y over Rational Field' and 'Multivariate Polynomial Ring in z, t over Rational Field' @@ -742,13 +754,17 @@ cdef class CoercionModel_cache_maps(CoercionModel): Rational Field sage: cm.division_parent(QQ) Rational Field - sage: cm.division_parent(ZZ['x']) + sage: ZZx = ZZ['x'] + sage: cm.division_parent(ZZx) Fraction Field of Univariate Polynomial Ring in x over Integer Ring - sage: cm.division_parent(GF(41)) + sage: K = GF(41) + sage: cm.division_parent(K) Finite Field of size 41 - sage: cm.division_parent(Integers(100)) + sage: Zmod100 = Integers(100) + sage: cm.division_parent(Zmod100) Ring of integers modulo 100 - sage: cm.division_parent(SymmetricGroup(5)) + sage: S5 = SymmetricGroup(5) + sage: cm.division_parent(S5) Symmetric group of order 5! as a permutation group """ try: @@ -1082,7 +1098,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: print g None - sage: f, g = cm.coercion_maps(ZZ['x'], QQ) + sage: ZZx = ZZ['x'] + sage: f, g = cm.coercion_maps(ZZx, QQ) sage: print f (map internal to coercion system -- copy before use) Ring morphism: @@ -1094,7 +1111,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): From: Rational Field To: Univariate Polynomial Ring in x over Rational Field - sage: cm.coercion_maps(QQ, GF(7)) is None + sage: K = GF(7) + sage: cm.coercion_maps(QQ, K) is None True Note that to break symmetry, if there is a coercion map in both @@ -1248,7 +1266,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): Otherwise, try and compute an appropriate cover:: - sage: cm.discover_coercion(ZZ['x,y'], RDF) + sage: ZZxy = ZZ['x,y'] + sage: cm.discover_coercion(ZZxy, RDF) ((map internal to coercion system -- copy before use) Call morphism: From: Multivariate Polynomial Ring in x, y over Integer Ring @@ -1307,24 +1326,26 @@ cdef class CoercionModel_cache_maps(CoercionModel): EXAMPLES:: sage: cm = sage.structure.element.get_coercion_model() - sage: cm.get_action(ZZ['x'], ZZ, operator.mul) + sage: ZZx = ZZ['x'] + sage: cm.get_action(ZZx, ZZ, operator.mul) Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring - sage: cm.get_action(ZZ['x'], ZZ, operator.imul) + sage: cm.get_action(ZZx, ZZ, operator.imul) Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring - sage: cm.get_action(ZZ['x'], QQ, operator.mul) + sage: cm.get_action(ZZx, QQ, operator.mul) Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring - sage: cm.get_action(QQ['x'], int, operator.mul) + sage: QQx = QQ['x'] + sage: cm.get_action(QQx, int, operator.mul) Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Rational Field with precomposition on right by Native morphism: From: Set of Python objects of type 'int' To: Integer Ring - sage: R. = QQ['x'] - sage: A = cm.get_action(R, ZZ, operator.div); A + sage: A = cm.get_action(QQx, ZZ, operator.div); A Right inverse action by Rational Field on Univariate Polynomial Ring in x over Rational Field with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field + sage: x = QQx.gen() sage: A(x+10, 5) 1/5*x + 2 @@ -1449,12 +1470,13 @@ cdef class CoercionModel_cache_maps(CoercionModel): Bug :trac:`17740`:: - sage: cm.discover_action(GF(5)['x'], ZZ, operator.div) + sage: R = GF(5)['x'] + sage: cm.discover_action(R, ZZ, operator.div) Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in x over Finite Field of size 5 with precomposition on right by Natural morphism: From: Integer Ring To: Finite Field of size 5 - sage: cm.bin_op(GF(5)['x'].gen(), 7, operator.div).parent() + sage: cm.bin_op(R.gen(), 7, operator.div).parent() Univariate Polynomial Ring in x over Finite Field of size 5 """ #print "looking", R, R, op, S, S diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index ead12a687b0..0adb72e1969 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -65,17 +65,19 @@ cdef class GenericAction(Action): """ TESTS:: - sage: sage.structure.coerce_actions.ActedUponAction(MatrixSpace(ZZ, 2), Cusps, True) + sage: M = MatrixSpace(ZZ,2) + sage: sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps - sage: sage.structure.coerce_actions.GenericAction(QQ, Zmod(6), True) + sage: Z6 = Zmod(6) + sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True) Traceback (most recent call last): ... NotImplementedError: Action not implemented. This will break if we tried to use it:: - sage: sage.structure.coerce_actions.GenericAction(QQ, Zmod(6), True, check=False) + sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True, check=False) Left action by Rational Field on Ring of integers modulo 6 """ @@ -94,10 +96,14 @@ cdef class GenericAction(Action): EXAMPLES:: - sage: A = sage.structure.coerce_actions.ActedUponAction(MatrixSpace(ZZ, 2), Cusps, True) + sage: M = MatrixSpace(ZZ,2) + sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) sage: A.codomain() Set P^1(QQ) of all cusps - sage: A = sage.structure.coerce_actions.ActOnAction(SymmetricGroup(3), QQ['x,y,z'], False) + + sage: S3 = SymmetricGroup(3) + sage: QQxyz = QQ['x,y,z'] + sage: A = sage.structure.coerce_actions.ActOnAction(S3, QQxyz, False) sage: A.codomain() Multivariate Polynomial Ring in x, y, z over Rational Field """ @@ -139,7 +145,8 @@ cdef class ActedUponAction(GenericAction): """ TESTS:: - sage: A = sage.structure.coerce_actions.ActedUponAction(MatrixSpace(ZZ, 2), Cusps, True) + sage: M = MatrixSpace(ZZ,2) + sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) sage: A.act(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) Infinity sage: A._call_(matrix(ZZ, 2, [1,0,2,-1]), Cusp(1,2)) @@ -160,13 +167,15 @@ def detect_element_action(Parent X, Y, bint X_on_left, X_el=None, Y_el=None): EXAMPLES:: sage: from sage.structure.coerce_actions import detect_element_action - sage: detect_element_action(ZZ['x'], ZZ, False) + sage: ZZx = ZZ['x'] + sage: M = MatrixSpace(ZZ,2) + sage: detect_element_action(ZZx, ZZ, False) Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring - sage: detect_element_action(ZZ['x'], QQ, True) + sage: detect_element_action(ZZx, QQ, True) Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring - sage: detect_element_action(Cusps, MatrixSpace(ZZ, 2), False) + sage: detect_element_action(Cusps, M, False) Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps - sage: detect_element_action(Cusps, MatrixSpace(ZZ, 2), True), + sage: detect_element_action(Cusps, M, True), (None,) sage: detect_element_action(ZZ, QQ, True), (None,) @@ -266,13 +275,17 @@ cdef class ModuleAction(Action): EXAMPLES:: sage: from sage.structure.coerce_actions import LeftModuleAction - sage: LeftModuleAction(ZZ, ZZ['x']) + sage: ZZx = ZZ['x'] + sage: QQx = QQ['x'] + sage: QQy = QQ['y'] + sage: ZZxy = ZZ['x']['y'] + sage: LeftModuleAction(ZZ, ZZx) Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring - sage: LeftModuleAction(ZZ, QQ['x']) + sage: LeftModuleAction(ZZ, QQx) Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Rational Field - sage: LeftModuleAction(QQ, ZZ['x']) + sage: LeftModuleAction(QQ, ZZx) Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring - sage: LeftModuleAction(QQ, ZZ['x']['y']) + sage: LeftModuleAction(QQ, ZZxy) Left scalar multiplication by Rational Field on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring The following tests against a problem that was relevant during work on @@ -351,11 +364,15 @@ cdef class ModuleAction(Action): EXAMPLES:: sage: from sage.structure.coerce_actions import LeftModuleAction, RightModuleAction - sage: A = LeftModuleAction(ZZ, ZZ['x']); A + sage: ZZx = ZZ['x'] + sage: A = LeftModuleAction(ZZ, ZZx); A Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring sage: A._repr_name_() 'scalar multiplication' - sage: RightModuleAction(GF(5), GF(5)[['t']]) + + sage: GF5 = GF(5) + sage: GF5t = GF5[['t']] + sage: RightModuleAction(GF5, GF5t) Right scalar multiplication by Finite Field of size 5 on Power Series Ring in t over Finite Field of size 5 """ return "scalar multiplication" @@ -587,7 +604,8 @@ cdef class IntegerMulAction(Action): EXAMPLES:: sage: from sage.structure.coerce_actions import IntegerMulAction - sage: act = IntegerMulAction(ZZ, GF(101)) + sage: GF101 = GF(101) + sage: act = IntegerMulAction(ZZ, GF101) sage: act(3, 9) 27 sage: act(3^689, 9) @@ -606,7 +624,8 @@ cdef class IntegerMulAction(Action): This used to hang before :trac:`17844`:: - sage: E = EllipticCurve(GF(5), [4,0]) + sage: GF5 = GF(5) + sage: E = EllipticCurve(GF5, [4,0]) sage: P = E.random_element() sage: (-2^63)*P (0 : 1 : 0) @@ -644,7 +663,8 @@ cdef class IntegerMulAction(Action): EXAMPLES:: sage: from sage.structure.coerce_actions import IntegerMulAction - sage: IntegerMulAction(ZZ, GF(5)) + sage: GF5 = GF(5) + sage: IntegerMulAction(ZZ, GF5) Left Integer Multiplication by Integer Ring on Finite Field of size 5 """ return "Integer Multiplication" From 34d755fa583fc3102e09fb57c3eba30296f98799 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 13 Apr 2015 11:26:14 +0200 Subject: [PATCH 218/665] Removed trailing whitespaces --- src/sage/coding/linear_code.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 56c42fd52e9..46f9f0751bf 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -699,7 +699,7 @@ class AbstractLinearCode(module.Module): This class contains all methods that can be used on Linear Codes and on Linear Codes families. - So, every Linear Code-related class should inherit from this abstract + So, every Linear Code-related class should inherit from this abstract class. This class provides: @@ -726,8 +726,8 @@ class AbstractLinearCode(module.Module): .. NOTE:: - AbstractLinearCode embeds some generic implementations of helper methods like ``__cmp__`` or ``__eq__``. - As they are designed to fit for every linear code, they mostly use the generator matrix + AbstractLinearCode embeds some generic implementations of helper methods like ``__cmp__`` or ``__eq__``. + As they are designed to fit for every linear code, they mostly use the generator matrix and thus can be long for certain families of code. In that case, overriding these methods is encouraged. """ @@ -736,7 +736,7 @@ def __init__(self, base_field, length): Initializes mandatory parameters for a Linear Code object. This method only exists for inheritance purposes as it initializes - parameters that need to be known by every linear code. An abstract + parameters that need to be known by every linear code. An abstract linear code object should never be created. INPUT: @@ -789,7 +789,7 @@ def __init__(self, base_field, length): self._length = length cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() facade_for = VectorSpace(base_field, self._length) - self.Element = type(facade_for.an_element()) #for when we made this a non-facade parent + self.Element = type(facade_for.an_element()) #for when we made this a non-facade parent Parent.__init__(self, base=base_field, facade=facade_for, category=cat) def _an_element_(self): @@ -3137,7 +3137,7 @@ def LinearCodeFromVectorSpace(V, d=None): class LinearCode(AbstractLinearCode): r""" - Linear codes over a finite field or finite ring. + Linear codes over a finite field or finite ring. A *linear code* is a subspace of a vector space over a finite field. It can be defined by one of its basis or equivalently a generator matrix (a `k From 8040d65fdbe325625417bb7e50f39d0dd56e1756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 11:24:27 -0400 Subject: [PATCH 219/665] 11111: trivial doctest update --- src/sage/categories/fields.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 522bcc0de50..8b34a662ff4 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -126,10 +126,8 @@ def _contains_helper(cls): sage: P. = QQ[] sage: Q = P.quotient(x^2+2) sage: Q.category() - Join of Category of integral domains - and Category of commutative algebras over Rational Field - and Category of subquotients of monoids - and Category of quotients of semigroups + Category of commutative no zero divisors quotients + of algebras over Rational Field sage: F = Fields() sage: F._contains_helper(Q) False From 25326fd0fdeef20514ebf7e053061d84254f8c19 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 13 Apr 2015 12:18:28 -0400 Subject: [PATCH 220/665] a few minor corrections --- src/sage/combinat/sf/macdonald.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 7cf7ec8fe4d..524427ee9ce 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -634,6 +634,7 @@ def Bmu( mu ): EXAMPLES:: + sage: from sage.combinat.sf.macdonald import Bmu sage: Bmu(Partition([2,1])) q + t + 1 sage: Bmu(SkewPartition([[3,3],[2]])) @@ -657,6 +658,7 @@ def cmunu1(mu, nu): EXAMPLES:: + sage: from sage.combinat.sf.macdonald import cmunu1 sage: cmunu1(Partition([2,1]),Partition([2])) (-t^2 + q)/(q - t) sage: cmunu1(Partition([2,1]),Partition([1,1])) @@ -664,7 +666,7 @@ def cmunu1(mu, nu): sage: Sym = SymmetricFunctions(QQ['q','t'].fraction_field()) sage: h = Sym.h() sage: Ht = Sym.macdonald().Ht() - sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) == cmunu(Partition([3,2,1]),nu) for nu in Partition([3,2,1]).down_list()) + sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) == cmunu1(Partition([3,2,1]),nu) for nu in Partition([3,2,1]).down_list()) True """ q,t = QQqt.gens() @@ -695,6 +697,7 @@ def cmunu(mu, nu): EXAMPLES:: + sage: from sage.combinat.sf.macdonald import cmunu sage: cmunu(Partition([2,1]),Partition([1])) q + t + 1 sage: cmunu(Partition([2,2]),Partition([1,1])) From fef786ff91822cf735894e80d9ebcdc86712c20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 13:32:20 -0400 Subject: [PATCH 221/665] 11111: Improved Algebras.Semisimple shorthand + improved and fix doctests accordingly --- src/sage/categories/algebras.py | 6 ++--- src/sage/categories/category_with_axiom.py | 4 +-- .../finite_dimensional_algebras_with_basis.py | 5 ++-- .../finite_dimensional_modules_with_basis.py | 6 ++--- src/sage/categories/finite_groups.py | 12 ++++----- src/sage/categories/groups.py | 2 +- src/sage/categories/modules_with_basis.py | 4 +-- src/sage/categories/semisimple_algebras.py | 27 ++++++++++++++++--- src/sage/categories/sets_cat.py | 6 ++--- 9 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 1ec4cb4a86a..5e81cee137a 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -100,9 +100,9 @@ def Semisimple(self): EXAMPLES:: - sage: Algebras(QQ).SemiSimple() + sage: Algebras(QQ).Semisimple() Category of semisimple algebras over Rational Field - sage: Algebras(QQ).WithBasis().FiniteDimensional().SemiSimple() + sage: Algebras(QQ).WithBasis().FiniteDimensional().Semisimple() Category of finite dimensional semisimple algebras with basis over Rational Field """ from sage.categories.semisimple_algebras import SemisimpleAlgebras @@ -112,7 +112,7 @@ def Semisimple(self): Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras') WithBasis = LazyImport('sage.categories.algebras_with_basis', 'AlgebrasWithBasis') #if/when Semisimple becomes an axiom - #Semisimple = LazyImport('sage.categories.semisimple_algebras', 'SemisimpleAlgebras') + Semisimple = LazyImport('sage.categories.semisimple_algebras', 'SemisimpleAlgebras') class ElementMethods: # TODO: move the content of AlgebraElement here or higher in the category hierarchy diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 90586546b9a..f2356920f20 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1646,9 +1646,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class and Category of finite dimensional algebras with basis over Rational Field and Category of finite set algebras over Rational Field sage: FiniteGroups().Algebras(QQ) - Join of Category of finite dimensional hopf algebras with basis over Rational Field - and Category of group algebras over Rational Field - and Category of finite set algebras over Rational Field + Category of finite group algebras over Rational Field """ #***************************************************************************** # Copyright (C) 2011-2014 Nicolas M. Thiery diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 41e4592a960..6ce4966ef62 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -15,7 +15,6 @@ from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.algebras import Algebras from sage.categories.associative_algebras import AssociativeAlgebras -from sage.categories.semisimple_algebras import SemisimpleAlgebras class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): r""" @@ -64,7 +63,7 @@ def radical_basis(self, cache_products=True): - a list of elements of ``self``. - .. SEEALSO:: :meth:`radical`, :class:`SemisimpleAlgebras` + .. SEEALSO:: :meth:`radical`, :class:`Algebras.Semisimple` EXAMPLES:: @@ -368,7 +367,7 @@ def center(self): sage: TestSuite(center).run() """ category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() - if self in SemisimpleAlgebras: + if self in Algebras.Semisimple: category = category.Semisimple() center = self.submodule(self.center_basis(), category=category, diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 83705d6affa..7f623f4ec8e 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -76,9 +76,9 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: x,y,a,b = F.basis() sage: A = F.annihilator([a + 3*b + 2*y]); A - Vector space of degree 4 and dimension 1 over Rational Field - Basis matrix: - [ 1 0 -1/2 -3/2] + Free module generated by {0} over Rational Field + sage: [b.lift() for b in A.basis()] + [-1/2*a - 3/2*b + x] Taking annihilator is order reversing for inclusion:: diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 238fb145059..052541f30be 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -194,19 +194,19 @@ def extra_super_categories(self): EXAMPLES:: - sage: FiniteGroups().Algebras(QQ).is_subcategory(SemisimpleAlgebras(QQ)) + sage: FiniteGroups().Algebras(QQ).is_subcategory(Algebras(QQ).Semisimple()) True - sage: FiniteGroups().Algebras(FiniteField(7)).is_subcategory(SemisimpleAlgebras(QQ)) + sage: FiniteGroups().Algebras(FiniteField(7)).is_subcategory(Algebras(QQ).Semisimple()) False - sage: FiniteGroups().Algebras(ZZ).is_subcategory(SemisimpleAlgebras(ZZ)) + sage: FiniteGroups().Algebras(ZZ).is_subcategory(Algebras(ZZ).Semisimple()) False - sage: FiniteGroups().Algebras(Fields()).is_subcategory(SemisimpleAlgebras(Fields())) + sage: FiniteGroups().Algebras(Fields()).is_subcategory(Algebras(Fields()).Semisimple()) False """ - from sage.categories.semisimple_algebras import SemisimpleAlgebras from sage.categories.fields import Fields K = self.base_ring() if (K in Fields) and K.characteristic() == 0: - return [SemisimpleAlgebras(self.base_ring())] + from sage.categories.algebras import Algebras + return [Algebras(self.base_ring()).Semisimple()] else: return [] diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 19a46c1e60d..112d794f695 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -707,7 +707,7 @@ def center_basis(self): EXAMPLES:: sage: SymmetricGroup(3).algebra(QQ).center_basis() - [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] + [(), (2,3) + (1,2) + (1,3), (1,2,3) + (1,3,2)] .. SEEALSO:: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 764c9a250db..044108a3d02 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -630,7 +630,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: S3A = S3.algebra(QQ) sage: basis = S3A.annihilator_basis(S3A.algebra_generators(), S3A.bracket) sage: basis - [B[()], B[(2,3)] + B[(1,2)] + B[(1,3)], B[(1,2,3)] + B[(1,3,2)]] + [(), (2,3) + (1,2) + (1,3), (1,2,3) + (1,3,2)] sage: center = S3A.submodule(basis, ....: category=AlgebrasWithBasis(QQ).Subobjects(), ....: already_echelonized=True) @@ -641,7 +641,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non sage: center.print_options(prefix='c') sage: c = center.basis() sage: c[1].lift() - B[(2,3)] + B[(1,2)] + B[(1,3)] + (2,3) + (1,2) + (1,3) sage: c[0]^2 c[0] sage: e = 1/6*(c[0]+c[1]+c[2]) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index bcc11d7bbe9..5539ac72dfb 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -2,12 +2,13 @@ Semisimple Algebras """ #***************************************************************************** -# Copyright (C) 2011 Nicolas M. Thiery +# Copyright (C) 2011-2015 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.misc.bindable_class import BoundClass from category_types import Category_over_base_ring from algebras import Algebras from sage.misc.cachefunc import cached_method @@ -19,7 +20,7 @@ class SemisimpleAlgebras(Category_over_base_ring): EXAMPLES:: - from sage.categories.semisimple_algebras import SemisimpleAlgebras + sage: from sage.categories.semisimple_algebras import SemisimpleAlgebras sage: C = SemisimpleAlgebras(QQ); C Category of semisimple algebras over Rational Field @@ -52,12 +53,31 @@ class SemisimpleAlgebras(Category_over_base_ring): sage: TestSuite(C).run() """ + @staticmethod + def __classget__(cls, base_category, base_category_class): + """ + Implement the shorthand ``Algebras(K).Semisimple()`` for ``SemisimpleAlgebras(K)``. + + This magic mimics the syntax of axioms for a smooth transition + if ``Semisimple`` becomes one. + + EXAMPLES:: + + sage: Algebras(QQ).Semisimple() + Category of semisimple algebras over Rational Field + sage: Algebras.Semisimple + + """ + if base_category is None: + return cls + return BoundClass(cls, base_category.base_ring()) + @cached_method def super_categories(self): """ EXAMPLES:: - sage: SemisimpleAlgebras(QQ).super_categories() + sage: Algebras(QQ).Semisimple().super_categories() [Category of algebras over Rational Field] """ R = self.base_ring() @@ -84,5 +104,6 @@ def radical_basis(self, **keywords): TESTS:: sage: A.radical_basis.__module__ + 'sage.categories.finite_dimensional_algebras_with_basis' """ return [] diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 119616318c7..d2aab446f27 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1449,11 +1449,11 @@ def algebra(self, base_ring, category=None): does not divide the characteristic of the base field, the algebra is semisimple:: - sage: SymmetricGroup(5).algebra(QQ) in SemisimpleAlgebras(QQ) + sage: SymmetricGroup(5).algebra(QQ) in Algebras(QQ).Semisimple() True - sage: CyclicPermutationGroup(10).algebra(FiniteField(5)) in SemisimpleAlgebras + sage: CyclicPermutationGroup(10).algebra(FiniteField(5)) in Algebras.Semisimple False - sage: CyclicPermutationGroup(10).algebra(FiniteField(7)) in SemisimpleAlgebras + sage: CyclicPermutationGroup(10).algebra(FiniteField(7)) in Algebras.Semisimple True From be16385b3fc7e72355624ca7d2a9ac9ed4857ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 15:25:07 -0400 Subject: [PATCH 222/665] 11111: make Modules.SubcategoryMethods.base_ring work with any subcategory of Modules --- src/sage/categories/modules.py | 49 +++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 4eaa56726de..d4a19d9f5eb 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -190,25 +190,11 @@ class SubcategoryMethods: @cached_method def base_ring(self): - """ + r""" Return the base ring (category) for ``self``. - This implements a ``base_ring`` method for join categories - which are subcategories of some ``Modules(K)``. - - .. TODO:: handle base being a category - - .. NOTE:: - - - This uses the fact that join categories are - flattened; thus some direct subcategory of - ``self`` should be a category over a base ring. - - Generalize this to any :class:`Category_over_base_ring`. - - Should this code be in :class:`JoinCategory`? - - This assumes that a subcategory of a - :class`~.category_types.Category_over_base_ring` is a - :class:`~.category.JoinCategory` or a - :class`~.category_types.Category_over_base_ring`. + This implements a ``base_ring`` method for all + subcategories ``Modules(K)``. EXAMPLES:: @@ -218,12 +204,31 @@ def base_ring(self): Rational Field sage: C.base_ring.__module__ 'sage.categories.modules' + + sage: C = Modules(Rings()) & Semigroups(); C + Join of Category of semigroups and Category of modules over rings + sage: C.base_ring() + Category of rings + sage: C.base_ring.__module__ + 'sage.categories.modules' + + sage: C = DescentAlgebra(QQ,3).B().category() + sage: C.base_ring.__module__ + 'sage.categories.modules' + sage: C.base_ring() + Rational Field + + sage: C = QuasiSymmetricFunctions(QQ).F().category() + sage: C.base_ring.__module__ + 'sage.categories.modules' + sage: C.base_ring() + Rational Field """ - assert isinstance(self, JoinCategory) - for x in self.super_categories(): - if isinstance(x, Category_over_base_ring): - return x.base_ring() - assert False, "some subcategory of {} should be a category over base ring".format(self) + for C in self.super_categories(): + # Is there a better way to ask if C is a subcategory of Modules? + if hasattr(C, "base_ring"): + return C.base_ring() + assert False, "some super category of {} should be a category over base ring".format(self) def TensorProducts(self): r""" From ae49353fae07038991a31f743286c9ffe9e1ecef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 15:32:22 -0400 Subject: [PATCH 223/665] 11111: Removed Modules.FiniteDimensional.WithBasis.ParentMethods.vectors_parent which was only temporarily useful --- .../finite_dimensional_modules_with_basis.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 7f623f4ec8e..9cc035a3fa1 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -34,19 +34,6 @@ class FiniteDimensionalModulesWithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: - @cached_method - def vectors_parent(self): - """ - Return the parent of the vectors created with ``x.to_vector()``. - - EXAMPLES:: - - sage: F = Algebras(QQ).FiniteDimensional().WithBasis().example() - sage: F.vectors_parent() - Vector space of dimension 4 over Rational Field - """ - return self.zero().to_vector().parent() - def annihilator(self, S, action=operator.mul, side='right', category=None): r""" INPUT: From 25f95a4f66a26587ec5ccc6a1228b41396c6cd79 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Mon, 13 Apr 2015 20:56:19 +0000 Subject: [PATCH 224/665] 11111: add references for the algorithm used to compute the radical basis --- .../finite_dimensional_algebras_with_basis.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6ce4966ef62..8f9d1beff2a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -52,7 +52,18 @@ def radical_basis(self, cache_products=True): This implementation handles algebras over fields of characteristic zero (using Dixon's lemma) or fields of - characteristic `p` in which we can compute `x^{1/p}`. + characteristic `p` in which we can compute `x^{1/p}` + [FR85], [Eb89]. + + REFERENCES: + + [Eb89] Eberly, Wayne. "Computations for algebras and group + representations." Ph.D. Thesis, University of Toronto, 1989. + + [FR85] Friedl, Katalin, and Lajos Rónyai. "Polynomial time + solutions of some problems of computational algebra." Proceedings + of the seventeenth annual ACM symposium on Theory of computing. + ACM, 1985. INPUT: @@ -233,7 +244,6 @@ def radical(self): .. TODO:: - Tell Sage that the radical is in fact an ideal; - - Add references; - Pickling by construction, as ``A.center()``; - Lazy evaluation of ``_repr_``. From 35d965a2d686c51afd69b277105bbd7a8d4ee172 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Mon, 13 Apr 2015 20:59:14 +0000 Subject: [PATCH 225/665] 11111: fix typos in annihilator documentation (finite_dimensional_modules_with_basis.py) --- .../categories/finite_dimensional_modules_with_basis.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 7f623f4ec8e..a428a8006ce 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -49,10 +49,12 @@ def vectors_parent(self): def annihilator(self, S, action=operator.mul, side='right', category=None): r""" + + INPUT: + - ``S`` -- a finite set of objects - ``side`` -- 'left' or 'right' (default: 'right') - - ``action`` -- a function (default: `operator.mul`) Assumptions: ``action`` takes elements of ``self`` as @@ -164,7 +166,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): sage: F.annihilator_basis([a+b], action = F.bracket) [x + y, a, b] - In particular one can computer the center of the + In particular one can compute the center of the algebra. In our example, it is reduced to the identity:: @@ -182,7 +184,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): mat = matrix(self.base_ring(), self.dimension(), 0) for s in S: mat = mat.augment(matrix(self.base_ring(), - [action(s,b).to_vector() for b in self.basis()])) + [action(s, b).to_vector() for b in self.basis()])) return map(self.from_vector, mat.left_kernel().basis()) class ElementMethods: From b024f0fcbee17f0a797b2f379394dbd5c0456502 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Mon, 13 Apr 2015 21:11:31 +0000 Subject: [PATCH 226/665] 11111: remove _conjugacy_classes_representatives_underlying_group from Groups.Algebras.ParentMethods --- src/sage/categories/groups.py | 41 +++++++---------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 112d794f695..515ab2a81e6 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -659,31 +659,6 @@ def algebra_generators(self): from sage.sets.family import Family return Family(self.group().gens(), self.term) - def _conjugacy_classes_representatives_underlying_group(self): - r""" - Return a complete list of representatives of conjugacy - classes of the underlying group. - - This works only for permutation groups. The ordering is - that given by GAP. - - EXAMPLES:: - - sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) - sage: SG = GroupAlgebras(QQ).example(G) - sage: SG._conjugacy_classes_representatives_underlying_group() - [(), (2,4), (1,2)(3,4), (1,2,3,4), (1,3)(2,4)] - - .. NOTE:: - - This function is overloaded for SymmetricGroupAlgebras to - return Permutations and not Elements of the symmetric group:: - - sage: SymmetricGroupAlgebra(ZZ,3)._conjugacy_classes_representatives_underlying_group() - [[2, 3, 1], [2, 1, 3], [1, 2, 3]] - """ - return self.group().conjugacy_classes_representatives() - def center_basis(self): r""" Return a basis of the center of the group algebra. @@ -701,7 +676,7 @@ def center_basis(self): .. WARNING:: - This method requires the underlying group to - have a method ``conjugacy_classes_representatives`` + have a method ``conjugacy_classes`` (every permutation group has one, thanks GAP!). EXAMPLES:: @@ -714,7 +689,7 @@ def center_basis(self): - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - return [sum([self(c) for c in conj]) for conj in + return [self.sum_of_monomials(conj) for conj in self.basis().keys().conjugacy_classes()] # Coalgebra structure @@ -808,12 +783,12 @@ class ElementMethods: def central_form(self): r""" - Return ``self`` in the canonical basis of the center + Return ``self`` expressed in the canonical basis of the center of the group algebra. INPUT: - - ``self`` -- a central element of the group algebra + - ``self`` -- an element of the center of the group algebra OUTPUT: @@ -826,8 +801,8 @@ def central_form(self): .. WARNING:: - This method requires the underlying group to - have a method - ``conjugacy_classes_representatives_underlying_group``. + have a method ``conjugacy_classes_representatives`` + (every permutation group has one, thanks GAP!). - This method does not check that the element is indeed central. Use the method :meth:`Monoids.Algebras.ElementMethods.is_central` @@ -859,8 +834,8 @@ def central_form(self): - :meth:`Monoids.Algebras.ElementMethods.is_central` """ from sage.combinat.free_module import CombinatorialFreeModule - Z = CombinatorialFreeModule(self.base_ring(), - self.parent()._conjugacy_classes_representatives_underlying_group()) + conj_classes_reps = self.basis().keys().conjugacy_classes_representatives() + Z = CombinatorialFreeModule(self.base_ring(), conj_classes_reps) return sum(self[i] * Z.basis()[i] for i in Z.basis().keys()) class CartesianProducts(CartesianProductsCategory): From 3017fae8e9e19d6b1fbdd2918180297e40e099a8 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Mon, 13 Apr 2015 16:31:49 -0700 Subject: [PATCH 227/665] methods and docstrings --- .../root_system/integrable_representations.py | 118 ++++++++++++++---- 1 file changed, 94 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index c9e3311a30b..b65063b0e40 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -3,7 +3,8 @@ """ #***************************************************************************** -# Copyright (C) 2014 Daniel Bump +# Copyright (C) 2014, 2105 Daniel Bump +# Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -108,7 +109,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]); v - Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] + The Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] sage: v.m((3,5,3)) 18 @@ -116,7 +117,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): and :meth:`from_weight` to convert between this internal representation and the weight lattice:: - sage: delta = v._Q.null_root() + sage: delta = v.null_root() sage: v.to_weight((4,3,2)) -3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta sage: v.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) @@ -147,6 +148,8 @@ def __init__(self, Lam): """ CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ)) + if not Lam.parent()._extended: + raise ValueError("The parent of %s must be an extended affine root lattice."%Lam) self._Lam = Lam self._P = Lam.parent() self._Q = self._P.root_system.root_lattice() @@ -185,11 +188,54 @@ def __init__(self, Lam): self._eps = {i: self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] for i in self._index_set} + def highest_weight(self): + """ + Returns the highest weight of the IntegrableRepresentation ``self``. + """ + return self._Lam + + def weight_lattice(self): + """ + Returns the Weight Lattice of ``self``. + + EXAMPLES:: + + sage: v=IntegrableRepresentation(RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: v.weight_lattice() + Extended weight lattice of the Root system of type ['E', 6, 1] + """ + + return self._P + + def root_lattice(self): + """ + Returns the Root Lattice of ``self``. + + EXAMPLES:: + sage: v=IntegrableRepresentation(RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: v=IntegrableRepresentation(RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: v.root_lattice() + Root lattice of the Root system of type ['F', 4, 1] + """ + return self._Q + + def null_root(self): + """ + Returns the nullroot of ``self``. + + EXAMPLES:: + sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v=IntegrableRepresentation(Lambda[0]) + sage: delta = v.null_root(); delta + alpha[0] + 3*alpha[1] + 2*alpha[2] + """ + return self._Q.null_root() + def __repr__(self): """ Return a string representation of ``self``. """ - return "Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) + return "The Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) def _inner_qq(self, qelt1, qelt2): """ @@ -226,15 +272,14 @@ def _inner_pq(self, pelt, qelt): mcp = pelt.monomial_coefficients() mcq = qelt.monomial_coefficients() zero = ZZ.zero() - return sum(mcp.get(i, zero) * mcq[i] / self._eps[i] - for i in mcq) # Only need non-zero entries + return sum(mcp.get(i, zero) * mcq[i] / self._eps[i] for i in mcq) def to_weight(self, n): """ Return the weight associated to the tuple ``n``. If ``n`` is the tuple `(n_1, n_2, \ldots)`, then the associated - weight is `\Lambda - \sum_i n_i alpha_i`, where `\Lambda` is the + weight is `\Lambda - sum_i n_i \alpha_i`, where `\Lambda` is the weight of the representation. """ alpha = self._P.simple_roots() @@ -244,7 +289,7 @@ def to_weight(self, n): def _from_weight_helper(self, mu): r""" - Return ``(n[0], n[1], ...)`` such that ``mu = \sum n[i]*alpha[i]``. + Return ``(n[0], n[1], ...)`` such that ``mu = sum n[i]*alpha[i]``. INPUT: @@ -269,7 +314,7 @@ def _from_weight_helper(self, mu): def from_weight(self, mu): """ - Return ``(n[0], n[1], ...)`` such that ``mu = Lam - \sum n[i]*alpha[i]`` + Return ``(n[0], n[1], ...)`` such that ``mu = Lam - sum n[i]*alpha[i]`` """ return self._from_weight_helper(self._Lam - mu) @@ -285,7 +330,7 @@ def s(self, n, i): def to_dominant(self, n): """ - Return a dominant weight of ``n`` obtained under reflections. + Return the dominant weight equivalent to ``n`` under the affine Weyl group. """ if n in self._ddict: return self._ddict[n] @@ -314,7 +359,7 @@ def to_dominant(self, n): next = True break - # We don't want any dominat weight to refer to itself in self._ddict + # We don't want any dominant weight to refer to itself in self._ddict # as this leads to an infinite loop with self.m() when the dominant # weight does not have a known multiplicity. v = path.pop() @@ -325,12 +370,7 @@ def to_dominant(self, n): def freudenthal_roots_imaginary(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of imaginary - roots `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. - - Lambda = self._P.fundamental_weights() - kp = min(ZZ(nu.symmetric_form(Lambda[i])) for i in self._index_set) - delta = self._Q.null_root() - return [u*delta for u in [1..kp]] + roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. """ l = self._from_weight_helper(nu) a = self._cartan_type.a() @@ -341,7 +381,7 @@ def freudenthal_roots_imaginary(self, nu): def freudenthal_roots_real(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of real positive - roots `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. + roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. """ ret = [] for al in self._classical_positive_roots: @@ -368,7 +408,7 @@ def freudenthal_roots(self, nu): def _freudenthal_accum(self, nu, al): """ - Helper method for something with computing the Freudenthal formula. + Helper method for computing the Freudenthal formula. """ ret = 0 n = list(self._from_weight_helper(self._Lam - nu)) @@ -386,7 +426,7 @@ def _freudenthal_accum(self, nu, al): ret += 2*mk*ip return ret - def m_freudenthal(self, n): + def _m_freudenthal(self, n): """ Compute the weight multiplicity using the Freudenthal multiplicity formula. """ @@ -403,7 +443,7 @@ def m_freudenthal(self, n): for al in self.freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank * self._freudenthal_accum(mu, al) if den == 0 and num == 0: - print "m_freudenthal","m: n=%s, num=den=0"%n.__repr__() + print "_m_freudenthal","m: n=%s, num=den=0"%n.__repr__() try: return ZZ(num / den) except: @@ -411,12 +451,28 @@ def m_freudenthal(self, n): def m(self, n): """ - Return the multiplicity. + INPUT: + + - ``n`` -- a representing a weight `\mu`. + + Return the multiplicity of the weight `\mu` in ``self``, where + `\mu = \Lambda - \sum_i n[i]\,\alpha_i``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: u = v.highest_weight()-v.null_root(); u + Lambda[0] - delta + sage: v.from_weight(u) + (1, 1, 2, 2, 3, 2, 1) + sage: v.m(v.from_weight(u)) + 6 """ # TODO: Make this non-recursive by implementing our own stack # The recursion follows: # - m - # - m_freudenthal + # - _m_freudenthal # - _freudenthal_accum if self._mdict.has_key(n): return self._mdict[n] @@ -425,7 +481,7 @@ def m(self, n): m = self.to_dominant(n) if self._mdict.has_key(m): return self._mdict[m] - ret = self.m_freudenthal(m) + ret = self._m_freudenthal(m) if ret is not None: self._mdict[n] = ret else: @@ -473,6 +529,20 @@ def strings(self, depth=12): """ Return the set of dominant maximal weights of ``self``, together with the string coefficients for each. + + OPTIONAL: + + - ``depth`` -- a parameter indicating how far to push computations + + The depth parameter defaults to 12. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(2*Lambda[0]).strings(depth=25) + 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 + 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 + """ # FIXME: This call to string should not be necessary as it is # highly redundant to generate the data for dominant_maximal From cdb55b4fa8fec1ece666f1fc663eafc1723410b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 22:38:16 -0400 Subject: [PATCH 228/665] 11111: fixed handling of the category in annihilator + updated doctests --- .../finite_dimensional_modules_with_basis.py | 116 ++++++++++++------ 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 9cc035a3fa1..07bfe76c131 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -36,37 +36,64 @@ class ParentMethods: def annihilator(self, S, action=operator.mul, side='right', category=None): r""" + Return the annihilator of a finite set. + INPUT: - - ``S`` -- a finite set of objects - - ``side`` -- 'left' or 'right' (default: 'right') - - ``action`` -- a function (default: `operator.mul`) + - ``S`` -- a finite set + + - ``action`` -- a function (default: :obj:`operator.mul`) + + - ``side`` -- 'left' or 'right' (default: 'right') + + - ``category`` -- a category + + Assumptions: - Assumptions: ``action`` takes elements of ``self`` as - first argument, and elements of ``S`` as second - argument, and is linear on its first argument - (typically it is bilinear). + - ``action`` takes elements of ``self`` as first argument + and elements of ``S`` as second argument; - Returns the supspace of the elements `x` of ``self`` - such that `action(x,s) = 0` for all `s\in S`. + - The codomain is any vector space, and ``action`` is + linear on its first argument; typically it is bilinear; - If ``side`` is 'left', then the order of the arguments - of ``action`` is reversed. + - If ``side`` is 'left', this is reversed. - TODO: double check the convention for ``left/right``. + OUTPUT: + + The subspace of the elements `x` of ``self`` such that + ``action(x,s) = 0`` for all `s\in S`. If ``side`` is + 'left' replace the above equation by ``action(s,x) = 0`. + + If ``self`` is a ring, action is an action of ``self`` on + a module `M` and `S` is a subset of `M`, we recover the + :Wikipedia:`Annihilator_%28ring_theory%29`. Similarly this + can be used to compute torsion or orthogonals. .. SEEALSO:: :meth:`annihilator_basis` for lots of examples. EXAMPLES:: sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: x,y,a,b = F.basis() sage: A = F.annihilator([a + 3*b + 2*y]); A Free module generated by {0} over Rational Field sage: [b.lift() for b in A.basis()] [-1/2*a - 3/2*b + x] + The category can be used to specify other properties of + this subspace, like that this is a subalgebra:: + + sage: center = F.annihilator(F.basis(), F.bracket, + ....: category=Algebras(QQ).Subobjects()) + sage: (e,) = center.basis() + sage: e.lift() + x + y + sage: e * e == e + True + Taking annihilator is order reversing for inclusion:: sage: A = F.annihilator([]); A .rename("A") @@ -74,32 +101,48 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): sage: Ay = F.annihilator([y]); Ay .rename("Ay") sage: Axy = F.annihilator([x,y]); Axy.rename("Axy") sage: P = Poset(([A, Ax, Ay, Axy], attrcall("is_submodule"))) - sage: P.cover_relations() - [[Axy, Ay], [Axy, Ax], [Ay, A], [Ax, A]] - + sage: sorted(P.cover_relations(), key=str) + [[Ax, A], [Axy, Ax], [Axy, Ay], [Ay, A]] """ - return self.submodule(self.annihilator_basis(S, action, side), already_echelonized=True) + return self.submodule(self.annihilator_basis(S, action, side), + already_echelonized=True, + category=category) def annihilator_basis(self, S, action=operator.mul, side='right'): """ + Return a basis of the annihilator of a finite set of elements. + + INPUT: + + - ``S`` -- a finite set of objects + + - ``action`` -- a function (default: :obj:`operator.mul`) + + - ``side`` -- 'left' or 'right' (default: 'right'): + on which side of ``self`` the elements of `S` acts. + + See :meth:`annihilator` for the assumptions and definition + of the annihilator. EXAMPLES: - By default, the action is the standard `*` - operation. So our first example is about an algebra:: + By default, the action is the standard `*` operation. So + our first example is about an algebra:: sage: F = FiniteDimensionalAlgebrasWithBasis(QQ).example(); F - An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: x,y,a,b = F.basis() In this algebra, multiplication on the right by `x` - kills all basis elements but `x`:: + annihilates all basis elements but `x`:: sage: x*x, y*x, a*x, b*x (x, 0, 0, 0) - So the annihilator is the subspace spanned by - `y`,`a`,and `b`:: + So the annihilator is the subspace spanned by `y`,`a`,and + `b`:: sage: F.annihilator_basis([x]) [y, a, b] @@ -140,25 +183,28 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): sage: F.annihilator_basis([a+3*b+2*x], side="left") [-1/2*a - 3/2*b + y] - By specifying an inner product, this method can be - used to compute the orthogonal of a subspace (TODO: - add an example). + By specifying an inner product, this method can be used to + compute the orthogonal of a subspace:: + + sage: x,y,a,b = F.basis() + sage: def scalar(u,v): return vector([sum(u[i]*v[i] for i in F.basis().keys())]) + sage: F.annihilator_basis([x+y, a+b], scalar) + [x - y, a - b] - By specifying instead the standard Lie bracket as - action, one can compute the commutator of a subspace - of `F`:: + By specifying the standard Lie bracket as action, one can + compute the commutator of a subspace of `F`:: sage: F.annihilator_basis([a+b], action = F.bracket) [x + y, a, b] - In particular one can computer the center of the - algebra. In our example, it is reduced to the - identity:: + In particular one can compute a basis of the center of the + algebra. In our example, it is reduced to the identity:: sage: F.annihilator_basis(F.algebra_generators(), action = F.bracket) [x + y] - .. SEEALSO:: :meth:`FiniteAlgebrasWithBasis.ParentMethods.center_basis`. + But see also + :meth:`FiniteDimensionalAlgebrasWithBasis.ParentMethods.center_basis`. """ # TODO: optimize this! from sage.matrix.constructor import matrix @@ -169,7 +215,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): mat = matrix(self.base_ring(), self.dimension(), 0) for s in S: mat = mat.augment(matrix(self.base_ring(), - [action(s,b).to_vector() for b in self.basis()])) + [action(s, b)._vector_() for b in self.basis()])) return map(self.from_vector, mat.left_kernel().basis()) class ElementMethods: @@ -255,7 +301,7 @@ def matrix(self, base_ring=None, side="left"): on_basis = self.on_basis() basis_keys = self.domain().basis().keys() m = matrix(base_ring, - [on_basis(x).to_vector() for x in basis_keys]) + [on_basis(x)._vector_() for x in basis_keys]) if side == "left": m = m.transpose() m.set_immutable() From 411f1a7841405e2271a654bd5a7e11d02cc35dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 22:41:25 -0400 Subject: [PATCH 229/665] 11111: finished merge --- .../finite_dimensional_algebras_with_basis.py | 14 +++++- src/sage/categories/groups.py | 43 ++++--------------- src/sage/combinat/symmetric_group_algebra.py | 8 ++++ 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6ce4966ef62..8f9d1beff2a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -52,7 +52,18 @@ def radical_basis(self, cache_products=True): This implementation handles algebras over fields of characteristic zero (using Dixon's lemma) or fields of - characteristic `p` in which we can compute `x^{1/p}`. + characteristic `p` in which we can compute `x^{1/p}` + [FR85], [Eb89]. + + REFERENCES: + + [Eb89] Eberly, Wayne. "Computations for algebras and group + representations." Ph.D. Thesis, University of Toronto, 1989. + + [FR85] Friedl, Katalin, and Lajos Rónyai. "Polynomial time + solutions of some problems of computational algebra." Proceedings + of the seventeenth annual ACM symposium on Theory of computing. + ACM, 1985. INPUT: @@ -233,7 +244,6 @@ def radical(self): .. TODO:: - Tell Sage that the radical is in fact an ideal; - - Add references; - Pickling by construction, as ``A.center()``; - Lazy evaluation of ``_repr_``. diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 112d794f695..f336fa1f223 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -659,31 +659,6 @@ def algebra_generators(self): from sage.sets.family import Family return Family(self.group().gens(), self.term) - def _conjugacy_classes_representatives_underlying_group(self): - r""" - Return a complete list of representatives of conjugacy - classes of the underlying group. - - This works only for permutation groups. The ordering is - that given by GAP. - - EXAMPLES:: - - sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) - sage: SG = GroupAlgebras(QQ).example(G) - sage: SG._conjugacy_classes_representatives_underlying_group() - [(), (2,4), (1,2)(3,4), (1,2,3,4), (1,3)(2,4)] - - .. NOTE:: - - This function is overloaded for SymmetricGroupAlgebras to - return Permutations and not Elements of the symmetric group:: - - sage: SymmetricGroupAlgebra(ZZ,3)._conjugacy_classes_representatives_underlying_group() - [[2, 3, 1], [2, 1, 3], [1, 2, 3]] - """ - return self.group().conjugacy_classes_representatives() - def center_basis(self): r""" Return a basis of the center of the group algebra. @@ -701,7 +676,7 @@ def center_basis(self): .. WARNING:: - This method requires the underlying group to - have a method ``conjugacy_classes_representatives`` + have a method ``conjugacy_classes`` (every permutation group has one, thanks GAP!). EXAMPLES:: @@ -714,8 +689,8 @@ def center_basis(self): - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - return [sum([self(c) for c in conj]) for conj in - self.basis().keys().conjugacy_classes()] + return [self.sum_of_monomials(conj) for conj in + self.basis().keys().conjugacy_classes()] # Coalgebra structure @@ -808,12 +783,12 @@ class ElementMethods: def central_form(self): r""" - Return ``self`` in the canonical basis of the center + Return ``self`` expressed in the canonical basis of the center of the group algebra. INPUT: - - ``self`` -- a central element of the group algebra + - ``self`` -- an element of the center of the group algebra OUTPUT: @@ -826,8 +801,8 @@ def central_form(self): .. WARNING:: - This method requires the underlying group to - have a method - ``conjugacy_classes_representatives_underlying_group``. + have a method ``conjugacy_classes_representatives`` + (every permutation group has one, thanks GAP!). - This method does not check that the element is indeed central. Use the method :meth:`Monoids.Algebras.ElementMethods.is_central` @@ -859,8 +834,8 @@ def central_form(self): - :meth:`Monoids.Algebras.ElementMethods.is_central` """ from sage.combinat.free_module import CombinatorialFreeModule - Z = CombinatorialFreeModule(self.base_ring(), - self.parent()._conjugacy_classes_representatives_underlying_group()) + conj_classes_reps = self.parent().basis().keys().conjugacy_classes_representatives() + Z = CombinatorialFreeModule(self.base_ring(), conj_classes_reps) return sum(self[i] * Z.basis()[i] for i in Z.basis().keys()) class CartesianProducts(CartesianProductsCategory): diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 0dc3b28f5e6..4eac700f8cc 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -190,6 +190,14 @@ def SymmetricGroupAlgebra(R, W): sage: SGA.group() is W True sage: TestSuite(SGA).run() + + sage: SG=SymmetricGroupAlgebra(ZZ,3) + sage: SG.group().conjugacy_classes_representatives() + [[1, 2, 3], [2, 1, 3], [2, 3, 1]] + + sage: SGg = SymmetricGroup(3).algebra(ZZ) + sage: SGg.group().conjugacy_classes_representatives() + [(), (1,2), (1,2,3)] """ from sage.rings.semirings.non_negative_integer_semiring import NN if W in NN: From 73e87cf07ae198ae518dd3892b25c62d6860c6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 23:07:37 -0400 Subject: [PATCH 230/665] 11111: replayed doc updated that should not have been unplayed --- src/sage/combinat/root_system/hecke_algebra_representation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index bb01389fd13..a351567ef7d 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -79,7 +79,7 @@ def __init__(self, domain, on_basis, cartan_type, q1, q2, q=1, side="right"): sage: domain = W.algebra(QQ) sage: action = lambda x,i: domain.monomial(x.apply_simple_reflection(i, side="right")) sage: HeckeAlgebraRepresentation(domain, action, CartanType(["A",2]), 1, -1) - A representation of the (1, -1)-Hecke algebra of type ['A', 2] on Group algebra of Symmetric group of order 3! as a permutation group over Rational Field + A representation of the (1, -1)-Hecke algebra of type ['A', 2] on Symmetric group algebra over Rational Field """ self._domain = domain self._Ti_on_basis = on_basis @@ -226,7 +226,7 @@ def on_basis(self, x, word, signs=None, scalar=None): sage: rho = HeckeAlgebraRepresentation(domain, action, CartanType(["A",2]), 1, -1) sage: rho.on_basis(W.one(), (1,2,1)) - B[(1,3)] + (1,3) sage: word = (1,2) sage: u = W.from_reduced_word(word) From 42a0a30259018e56a2432046dcf87dc6e2337afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 23:08:10 -0400 Subject: [PATCH 231/665] 11111: doctest update --- src/sage/rings/polynomial/polynomial_quotient_ring.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 1507485f1f0..62af5f1a738 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -238,10 +238,8 @@ class of the quotient ring and its newly created elements. sage: P. = QQ[] sage: Q = P.quotient(x^2+2) sage: Q.category() - Join of Category of integral domains - and Category of commutative algebras over Rational Field - and Category of subquotients of monoids - and Category of quotients of semigroups + Category of commutative no zero divisors + quotients of algebras over Rational Field The test suite passes:: @@ -264,7 +262,8 @@ class of the category, and store the current class of the quotient sage: Q in Fields() True sage: Q.category() - Join of Category of fields and Category of commutative algebras over Rational Field and Category of subquotients of monoids and Category of quotients of semigroups + Category of commutative division no zero divisors + quotients of algebras over Rational Field sage: first_class == Q.__class__ False sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] From 2d64d41e165a4247e294030343a0e1c4a85720b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 13 Apr 2015 23:08:29 -0400 Subject: [PATCH 232/665] 11111: fixed typo --- src/sage/rings/quotient_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 9c487ff3b30..a3ed52dc8fd 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -45,7 +45,7 @@ z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) of Free Algebra on 3 generators (x, y, z) over Rational Field -Free algebras have a custom quotient method that seves at creating +Free algebras have a custom quotient method that serves at creating finite dimensional quotients defined by multiplication matrices. We are bypassing it, so that we obtain the default quotient:: From 451135be6a918321c1f3a3ee889ad069f4711d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 14 Apr 2015 08:51:11 +0200 Subject: [PATCH 233/665] trac #18132 reviewer's comments on name and doc --- src/sage/combinat/binary_tree.py | 12 ++++++------ src/sage/combinat/interval_posets.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 392be353863..4e0dc035b86 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1972,9 +1972,9 @@ def tamari_succ(self): [B([g, self[1]]) for g in self[0].tamari_succ()] + [B([self[0], d]) for d in self[1].tamari_succ()]) - def possible_cut_shapes(self): + def single_edge_cut_shapes(self): """ - Return the list of possible cut shapes for the binary tree. + Return the list of possible single-edge cut shapes for the binary tree. This is used in :meth:`sage.combinat.interval_posets.TamariIntervalPoset.is_new`. @@ -1989,7 +1989,7 @@ def possible_cut_shapes(self): Here `m` is the node number of the root-tree `R`, `n` the node number of the sub-tree `S`. The integer `i` is the index of the leaf of `R` on which `S` was grafted. The leaves of `R` are - numbered starting from `1`, hence `1 leq i \ leq m+1`. + numbered starting from `1`, hence `1 leq i \leq m+1`. In fact, each of `m` and `n` determines the other, as the total node number is the node number of ``self``. @@ -1997,7 +1997,7 @@ def possible_cut_shapes(self): EXAMPLES:: sage: BT = BinaryTrees(3) - sage: [t.possible_cut_shapes() for t in BT] + sage: [t.single_edge_cut_shapes() for t in BT] [[(2, 3, 1), (1, 2, 2)], [(2, 2, 1), (1, 2, 2)], [(2, 1, 1), (2, 3, 1)], @@ -2010,11 +2010,11 @@ def possible_cut_shapes(self): R = right.node_number() if L: resu += [(m + R + 1, i, n) - for m, i, n in left.possible_cut_shapes()] + for m, i, n in left.single_edge_cut_shapes()] resu += [(R + 1, 1, L)] if R: resu += [(m + L + 1, i + L + 1, n) - for m, i, n in right.possible_cut_shapes()] + for m, i, n in right.single_edge_cut_shapes()] resu += [(L + 1, L + 2, R)] return resu diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 0977a55caaf..f565c422ec9 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -2048,7 +2048,7 @@ def is_new(self): Here 'new' means that the interval is not contained in any proper facet of the associahedra. - They have been considered in [ChapTamari08]_. + They have been considered in section 9 of [ChapTamari08]_. EXAMPLES:: @@ -2056,8 +2056,8 @@ def is_new(self): sage: len([u for u in TIP4 if u.is_new()]) 12 """ - c_up = self.upper_binary_tree().possible_cut_shapes() - c_down = self.lower_binary_tree().possible_cut_shapes() + c_up = self.upper_binary_tree().single_edge_cut_shapes() + c_down = self.lower_binary_tree().single_edge_cut_shapes() return not any(x in c_up for x in c_down) From ad18e8efae471c06f850a9cec7f6902889c7ba54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 08:51:21 -0400 Subject: [PATCH 234/665] 11111: sage.modules.subquotient_module_with_basis -> sage.modules.with_basis.subquotient --- .../subquotient.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/sage/modules/{subquotient_module_with_basis.py => with_basis/subquotient.py} (100%) diff --git a/src/sage/modules/subquotient_module_with_basis.py b/src/sage/modules/with_basis/subquotient.py similarity index 100% rename from src/sage/modules/subquotient_module_with_basis.py rename to src/sage/modules/with_basis/subquotient.py From b83cfe497195fe7298cb37e9c227c0e63f8c90fd Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 20 Jan 2015 11:20:33 +0100 Subject: [PATCH 235/665] #18189 fix return type of real_roots.root_bounds... ...and related methods. They used to return RealNumber's except in some cases where 0 was returned as int(0). --- src/sage/rings/polynomial/real_roots.pyx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index 52374420859..fb3a23efc62 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -2156,7 +2156,7 @@ def maximum_root_first_lambda(p): sage: maximum_root_first_lambda((x-1)*(x-2)*(x-3)) 6.00000000000001 sage: maximum_root_first_lambda((x+1)*(x+2)*(x+3)) - 0 + 0.000000000000000 sage: maximum_root_first_lambda(x^2 - 1) 1.00000000000000 """ @@ -2180,6 +2180,13 @@ def cl_maximum_root_first_lambda(cl): sage: from sage.rings.polynomial.real_roots import * sage: cl_maximum_root_first_lambda([RIF(-1), RIF(0), RIF(1)]) 1.00000000000000 + + TESTS:: + + sage: bnd = cl_maximum_root_first_lambda(map(RIF, [0, 0, 0, 14, 1])) + sage: bnd, bnd.parent() + (0.000000000000000, + Real Field with 53 bits of precision and rounding RNDU) """ n = len(cl) - 1 assert(cl[n] > 0) @@ -2210,7 +2217,8 @@ def cl_maximum_root_first_lambda(cl): pending_pos_exp = j posCounter = posCounter+1 - if len(neg) == 0: return 0 + if len(neg) == 0: + return RIF._upper_field().zero() max_ub_log = RIF('-infinity') for j in xrange(len(neg)): @@ -2311,9 +2319,9 @@ def root_bounds(p): sage: root_bounds((x-1)*(x-2)*(x-3)) (0.545454545454545, 6.00000000000001) sage: root_bounds(x^2) - (0, 0) + (0.000000000000000, 0.000000000000000) sage: root_bounds(x*(x+1)) - (-1.00000000000000, 0) + (-1.00000000000000, 0.000000000000000) sage: root_bounds((x+2)*(x-3)) (-2.44948974278317, 3.46410161513776) sage: root_bounds(x^995 * (x^2 - 9999) - 1) @@ -2336,7 +2344,10 @@ def root_bounds(p): zero_roots = zero_roots + 1 n = n-1 - if n == 0: return (0, 0) + if n == 0: + # not RIF.zero().endpoints() because of MPFI's convention that the + # upper bound is -0. + return RIF._lower_field().zero(), RIF._upper_field().zero() ub = cl_maximum_root(cl) From ad6aa5f1d1a72b1fdcb41c73c4bca3d72df799e3 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 14 Apr 2015 15:47:30 +0200 Subject: [PATCH 236/665] #18162 remove java3d from the ref manual --- src/doc/en/reference/plot3d/index.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/plot3d/index.rst b/src/doc/en/reference/plot3d/index.rst index 16cbae41e7a..1855ae433ce 100644 --- a/src/doc/en/reference/plot3d/index.rst +++ b/src/doc/en/reference/plot3d/index.rst @@ -19,11 +19,13 @@ sage/plot/plot3d/texture sage/plot/plot3d/index_face_set - sage/plot/java3d sage/plot/plot3d/help sage/plot/plot3d/implicit_surface sage/plot/plot3d/shapes sage/plot/plot3d/transform sage/plot/plot3d/tri_plot +.. broken, see #16647 +.. sage/plot/java3d + .. include:: ../footer.txt From b0e162bd8d1f8a7841eff1dd268514670dbc9707 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Tue, 14 Apr 2015 15:59:24 +0000 Subject: [PATCH 237/665] 11111: fix typos; improve documentation for submodule --- .../finite_dimensional_modules_with_basis.py | 7 +-- src/sage/categories/modules.py | 2 +- src/sage/categories/modules_with_basis.py | 57 +++++++++++++++++-- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 07bfe76c131..c1bd82c6143 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -64,7 +64,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): ``action(x,s) = 0`` for all `s\in S`. If ``side`` is 'left' replace the above equation by ``action(s,x) = 0`. - If ``self`` is a ring, action is an action of ``self`` on + If ``self`` is a ring, ``action`` an action of ``self`` on a module `M` and `S` is a subset of `M`, we recover the :Wikipedia:`Annihilator_%28ring_theory%29`. Similarly this can be used to compute torsion or orthogonals. @@ -141,8 +141,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): sage: x*x, y*x, a*x, b*x (x, 0, 0, 0) - So the annihilator is the subspace spanned by `y`,`a`,and - `b`:: + So the annihilator is the subspace spanned by `y`, `a`, and `b`:: sage: F.annihilator_basis([x]) [y, a, b] @@ -154,7 +153,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): sage: F.annihilator_basis([a]) [y, a, b] - On the other hand, `y` kills only `x`:: + On the other hand, `y` annihilates only `x`:: sage: F.annihilator_basis([y]) [x] diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index d4a19d9f5eb..72dbdae5215 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -194,7 +194,7 @@ def base_ring(self): Return the base ring (category) for ``self``. This implements a ``base_ring`` method for all - subcategories ``Modules(K)``. + subcategories of ``Modules(K)``. EXAMPLES:: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 044108a3d02..a5fb017b66a 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -566,29 +566,45 @@ def _repr_(self): def echelonize(self, gens): """ + A basis in echelon form of the subspace spanned by a finite set of + elements. + + INPUT: + + - ``gens`` -- a finite set of elements of ``self`` + + OUTPUT: + + A list of elements of ``self`` whose expressions as vectors + is a matrix in echelon form. EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: X.echelonize([x[0]-x[1], x[0]-x[2],x[1]-x[2]]) + sage: V = X.echelonize([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V [x[0] - x[2], x[1] - x[2]] + sage: matrix(map(vector, V)) + [ 1 0 -1] + [ 0 1 -1] """ from sage.matrix.constructor import matrix mat = matrix([g.to_vector() for g in gens]) return [self.from_vector(v) for v in mat.row_space().basis()] - def submodule(self, gens, check = False, already_echelonized=False, category=None): + def submodule(self, gens, check=False, already_echelonized=False, category=None): r""" - Construct the `R`-sub free module spanned by ``gens``. + The submodule spanned by a finite set of elements. INPUT: - ``gens`` -- a list or family of elements of ``self`` + - ``check`` -- (default: True) whether to verify that the elements of ``gens`` are in ``self``. + - ``already_echelonized`` -- (default: ``False``) whether - the elements of gens are already in (not necessarily + the elements of ``gens`` are already in (not necessarily reduced) echelon form. If ``already_echelonized`` is ``False``, then the @@ -604,11 +620,17 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non The basis of the submodule uses the same index set as the generators, and the lifting map sends `y_i` to `gens[i]`. - EXAMPLES:: + EXAMPLES: + + We construct a submodule of the free `\QQ`-module generated by + `x_0, x_1, x_2`. The submodule is spanned by `y_0 = x_0 - x_1` and + `y_1 - x_1 - x_2`, and its basis elements are indexed by `0` and `1`:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: Y = X.submodule([x[0]-x[1], x[1]-x[2]], already_echelonized=True) + sage: gens = [x[0] - x[1], x[1] - x[2]]; gens + [x[0] - x[1], x[1] - x[2]] + sage: Y = X.submodule(gens, already_echelonized=True) sage: Y.print_options(prefix='y'); Y Free module generated by {0, 1} over Rational Field sage: y = Y.basis() @@ -623,6 +645,29 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non ... ValueError: x[0] is not in the image + By using a family to specify a basis of the submodule, we obtain a + submodule whose index set coincides with the index set of the family:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: gens = Family({1 : x[0] - x[1], 2: x[1] - x[2]}); gens + sage: Y = X.submodule(gens, already_echelonized=True) + sage: Y.print_options(prefix='y'); Y + Free module generated by {1, 2} over Rational Field + sage: y = Y.basis() + sage: y[1] + y[1] + sage: y[1].lift() + x[0] - x[1] + sage: y[2].lift() + x[1] - x[2] + sage: Y.retract(x[0]-x[2]) + y[1] + y[2] + sage: Y.retract(x[0]) + Traceback (most recent call last): + ... + ValueError: x[0] is not in the image + We now implement by hand the center of the algebra of the symmetric group `S_3`:: From c856c6885cae4fa0a0a4ad8c204d2a8439b1ec6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 12:01:48 -0400 Subject: [PATCH 238/665] 11111: finished previous commit + doc --- src/sage/categories/modules_with_basis.py | 6 +++--- src/sage/modules/with_basis/subquotient.py | 23 +++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 044108a3d02..7ecc2797543 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -659,7 +659,7 @@ def submodule(self, gens, check = False, already_echelonized=False, category=Non """ if not already_echelonized: gens = self.echelonize(gens) - from sage.modules.subquotient_module_with_basis import SubModuleWithBasis + from sage.modules.with_basis.subquotient import SubModuleWithBasis return SubModuleWithBasis(gens, ambient=self, category=category) def quotient(self, submodule, check=False, already_echelonized=False, category=None): @@ -669,7 +669,7 @@ def quotient(self, submodule, check=False, already_echelonized=False, category=N INPUT: - ``submodule`` -- a free submodule of ``self``, or something that can - be turned into one via self.submodule(submodule). + be turned into one via ``self.submodule(submodule)``. - ``check``, ``already_echelonized`` -- passed down to :meth:`submodule`, which see .. WARNING:: @@ -693,7 +693,7 @@ def quotient(self, submodule, check=False, already_echelonized=False, category=N sage: Y.retract(x[0]+2*x[1]) 3*y[2] """ - from sage.modules.subquotient_module_with_basis import SubModuleWithBasis, QuotientModuleWithBasis + from sage.modules.with_basis.subquotient import SubModuleWithBasis, QuotientModuleWithBasis if not isinstance(submodule, SubModuleWithBasis): submodule = self.submodule(submodule, check=check, already_echelonized=already_echelonized) diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index b9db95760bd..2289aacc7af 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -16,6 +16,18 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): r""" A class for quotients of a module with basis by a submodule. + + INPUT: + + - ``submodule`` -- a submodule + - ``category`` -- a category (default: ``ModulesWithBasis(submodule.base_ring())``) + + ``submodule`` is typically :class:`SubModuleWithBasis` + + # FIXME: The following currently works only if: + # - The ambient space is finite dimensional + # - The embedding is unitriangular + TODO: polish """ @staticmethod def __classcall_private__(cls, submodule, category=None): @@ -24,7 +36,7 @@ def __classcall_private__(cls, submodule, category=None): TESTS:: - sage: from sage.modules.subquotient_module_with_basis import QuotientModuleWithBasis + sage: from sage.modules.with_basis.subquotient import QuotientModuleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) sage: J1 = QuotientModuleWithBasis(I) @@ -41,7 +53,7 @@ def __init__(self, submodule, category): r""" TESTS:: - sage: from sage.modules.subquotient_module_with_basis import QuotientModuleWithBasis + sage: from sage.modules.with_basis.subquotient import QuotientModuleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) sage: Y = QuotientModuleWithBasis(I) @@ -58,9 +70,6 @@ def __init__(self, submodule, category): embedding = submodule.lift # Morphism that computes normal forms module submodule self._normal = embedding.cokernel_projection() - # FIXME: The following currently works only if: - # - The ambient space is finite dimensional - # - The embedding is unitriangular indices = embedding.cokernel_basis_indices() CombinatorialFreeModule.__init__(self, submodule.base_ring(), indices, @@ -133,7 +142,7 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts TESTS:: - sage: from sage.modules.subquotient_module_with_basis import SubModuleWithBasis + 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) @@ -152,7 +161,7 @@ def __init__(self, basis, ambient, category): r""" TESTS:: - sage: from sage.modules.subquotient_module_with_basis import SubModuleWithBasis + sage: from sage.modules.with_basis.subquotient import SubModuleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: ybas = (x[0]-x[1], x[1]-x[2]) sage: Y = SubModuleWithBasis(ybas, X) From 9e8dc213e8f49a022fbce469faaa7a36093ee6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 13:07:57 -0400 Subject: [PATCH 239/665] 11111: ReST fix --- src/sage/categories/finite_dimensional_modules_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index c1bd82c6143..c78e9d29c9d 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -62,7 +62,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): The subspace of the elements `x` of ``self`` such that ``action(x,s) = 0`` for all `s\in S`. If ``side`` is - 'left' replace the above equation by ``action(s,x) = 0`. + 'left' replace the above equation by ``action(s,x) = 0``. If ``self`` is a ring, ``action`` an action of ``self`` on a module `M` and `S` is a subset of `M`, we recover the From c1f54b123cb7e0cc691b93e72eb6082f39ac86e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 13:08:27 -0400 Subject: [PATCH 240/665] 11111: switch to utf-8 --- src/sage/categories/finite_dimensional_algebras_with_basis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 8f9d1beff2a..6c2cfa3b6dd 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -1,9 +1,10 @@ +# -*- coding: utf-8 -*- r""" Finite dimensional algebras with basis """ #***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) -# 2011-2015 Nicolas M. Thiery +# 2011-2015 Nicolas M. Thiéry # 2011-2015 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) From bc5f46ee87bcc6cf2ee24dcfc19a21a918c9b0cf Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 13:22:39 -0400 Subject: [PATCH 241/665] fixed case where t=1, the method for expanding in H or Ht basis could not handle this case --- src/sage/combinat/sf/macdonald.py | 32 +++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 524427ee9ce..179ecd6cb16 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1277,13 +1277,19 @@ def _m_to_self( self, f ): McdH[2, 1] """ - g = f(self._m([1])*(1-self.t)) + if self.t==1: + subsval = 1/self.q + fl = lambda x: x.conjugate() + else: + subsval = self.t + fl = lambda x: x + g = f.theta_qt(q=subsval,t=0) out = {} while not g.is_zero(): sprt = g.support() - Hmu = self._self_to_m(self(sprt[-1]))(self._m([1])*(1-self.t)) - out[sprt[-1]] = g.coefficient(sprt[-1])/Hmu.coefficient(sprt[-1]) - g -= out[sprt[-1]]*Hmu + Hmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval,t=0) + out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1])/Hmu.coefficient(sprt[-1])) + g -= out[fl(sprt[-1])]*Hmu return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): @@ -1415,6 +1421,10 @@ def _m_to_self( self, f ): is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading coefficient of the expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to the leading coefficient of `c_\mu^{-1} f[X(t-1)]`. + + If `t=1`, we must appeal to another triangularity since ``Ht`` is (usually) + still a basis, however `{\tilde H}_\mu[X(t-1)]=0`. In this case we assume that + it is a basis and INPUT: @@ -1443,13 +1453,19 @@ def _m_to_self( self, f ): McdHt[2, 1] """ - g = f(self._m([1])*(self.t-1)) + if self.t==1: + subsval = 1/self.q + fl = lambda x: x.conjugate() + else: + subsval = 1/self.t + fl = lambda x: x + g = f.theta_qt(q=subsval,t=0) out = {} while not g.is_zero(): sprt = g.support() - Htmu = self._self_to_m(self(sprt[-1]))(self._m([1])*(self.t-1)) - out[sprt[-1]] = self._base(g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1])) - g -= out[sprt[-1]]*Htmu + Htmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval,t=0) + out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1])) + g -= out[fl(sprt[-1])]*Htmu return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): From 5612be247730001756f49a67f70d9eaa9627257c Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 13:59:47 -0400 Subject: [PATCH 242/665] corrected a few doc tests where --c==c --- src/sage/combinat/sf/macdonald.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 179ecd6cb16..5007f379374 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -445,7 +445,7 @@ def H(self): sage: H = Sym.macdonald().H() sage: s = Sym.schur() sage: H(s([2])) - ((-q)/(-q*t+1))*McdH[1, 1] + (1/(-q*t+1))*McdH[2] + (q/(q*t-1))*McdH[1, 1] - (1/(q*t-1))*McdH[2] """ return MacdonaldPolynomials_h(self) @@ -894,7 +894,7 @@ def _multiply(self, left, right): sage: J._multiply( J[1], J[2] ) ((-q^2+1)/(-q^2*t+1))*McdJ[2, 1] + ((-t+1)/(-q^2*t+1))*McdJ[3] sage: H._multiply( H[1], H[2] ) - ((-q^2+1)/(-q^2*t+1))*McdH[2, 1] + ((-t+1)/(-q^2*t+1))*McdH[3] + ((q^2-1)/(q^2*t-1))*McdH[2, 1] + ((-t+1)/(-q^2*t+1))*McdH[3] sage: P._multiply( P[1], P[2] ) ((-q^3*t^2+q*t^2+q^2-1)/(-q^3*t^2+q^2*t+q*t-1))*McdP[2, 1] + McdP[3] sage: Q._multiply(Q[1],Q[2]) @@ -1271,9 +1271,9 @@ def _m_to_self( self, f ): sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) sage: x = Sym.base_ring().gen() - sage: H = Sym.macdonald(q=x,t=1/x).H() + sage: H = Sym.macdonald(q=x,t=1).H() sage: m = Sym.m() - sage: H(((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3]) + sage: H((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) McdH[2, 1] """ @@ -1447,9 +1447,9 @@ def _m_to_self( self, f ): sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) sage: x = Sym.base_ring().gen() - sage: Ht = Sym.macdonald(q=x,t=1/x).Ht() + sage: Ht = Sym.macdonald(q=x,t=1).Ht() sage: m = Sym.m() - sage: Ht(((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3]) + sage: Ht((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) McdHt[2, 1] """ From 849b7f5063def40b1055d03527803578724fff67 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 14:51:01 -0400 Subject: [PATCH 243/665] corrected one doc test in sfa.py --- 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 078f5c8da88..5a2c8dd2342 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3111,7 +3111,7 @@ def omega_qt(self,q = None,t = None): sage: H([1,1]).omega_qt(q,t) ((2*q^2-2*q*t-2*q+2*t)/(t^3-t^2-t+1))*McdH[1, 1] + ((q-1)/(t-1))*McdH[2] sage: H([1,1]).omega_qt(t,q) - ((t^3-t^2-t+1)/(q^3-q^2-q+1))*McdH[2] + ((-t^3+t^2+t-1)/(-q^3+q^2+q-1))*McdH[2] sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) sage: S = Sym.macdonald().S() sage: S([1,1]).omega_qt() From 9ba7893a61e4783b106cd13ad61e1190d77d901d Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 14:54:04 -0400 Subject: [PATCH 244/665] remove two long time comments --- src/sage/combinat/sf/macdonald.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 5007f379374..6d56d1130d6 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -964,9 +964,9 @@ def nabla(self, q=None, t=None, power=1): ((t^2+q-t-1)/(q*t-1))*McdH[1, 1] + ((-t^3+t^2+t-1)/(q*t-1))*McdH[2] sage: H(0).nabla() 0 - sage: H([2,2,1]).nabla(t=1/H.t) # long time (4s on sage.math, 2012) + sage: H([2,2,1]).nabla(t=1/H.t) q^2/t^4*McdH[2, 2, 1] - sage: H([2,2,1]).nabla(t=1/H.t,power=-1) # long time (4s on sage.math, 2013) + sage: H([2,2,1]).nabla(t=1/H.t,power=-1) t^4/q^2*McdH[2, 2, 1] """ parent = self.parent() From 7533c39947298609eae718e22c12f7d8d62d2089 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 14 Apr 2015 13:11:44 -0700 Subject: [PATCH 245/665] _inner_pp method added and doctests --- .../root_system/integrable_representations.py | 75 +++++++++++++++++-- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index b65063b0e40..d668a325f96 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -19,7 +19,7 @@ from sage.combinat.root_system.weight_space import WeightSpace from sage.rings.all import ZZ, QQ from sage.misc.all import cached_method -from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.constructor import Matrix from sage.functions.other import floor # TODO: Make this a proper parent and implement actions @@ -184,9 +184,12 @@ def __init__(self, Lam): for al in self._Q.classical().roots()] self._classical_positive_roots = [from_cl_root(al) for al in self._Q.classical().positive_roots()] - self._eps = {i: self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] for i in self._index_set} + self._a = self._cartan_type.a() + self._ac = self._cartan_type.dual().a() + E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical]) + self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse() def highest_weight(self): """ @@ -240,6 +243,19 @@ def __repr__(self): def _inner_qq(self, qelt1, qelt2): """ Symmetric form between two elements of the root lattice. + + EXAMPLES:: + + sage: P = RootSystem(['F',4,1]).weight_lattice(extended=true) + sage: Lambda = P.fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: alpha = v.root_lattice().simple_roots() + sage: Matrix([[v._inner_qq(alpha[i], alpha[j]) for j in v._index_set] for i in v._index_set]) + [ 2 -1 0 0 0] + [ -1 2 -1 0 0] + [ 0 -1 2 -1 0] + [ 0 0 -1 1 -1/2] + [ 0 0 0 -1/2 1] .. WARNING: @@ -248,7 +264,7 @@ def _inner_qq(self, qelt1, qelt2): and it will be wrong. To make this code robust, parents should be checked. This is not done since in the application the parents are known, so checking would unnecessarily slow - us down. += us down. """ mc1 = qelt1.monomial_coefficients() mc2 = qelt2.monomial_coefficients() @@ -259,7 +275,7 @@ def _inner_qq(self, qelt1, qelt2): def _inner_pq(self, pelt, qelt): """ - Symmetric form between an element of the weight and root lattices + Symmetric form between an element of the weight and root lattices. .. WARNING: @@ -268,12 +284,60 @@ def _inner_pq(self, pelt, qelt): this code robust, parents should be checked. This is not done since in the application the parents are known, so checking would unnecessarily slow us down. + + EXAMPLES:: + + sage: P = RootSystem(['F',4,1]).weight_lattice(extended=true) + sage: Lambda = P.fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: alpha = v.root_lattice().simple_roots() + sage: Matrix([[v._inner_pq(P(alpha[i]), alpha[j]) for j in v._index_set] for i in v._index_set]) + [ 2 -1 0 0 0] + [ -1 2 -1 0 0] + [ 0 -1 2 -1 0] + [ 0 0 -1 1 -1/2] + [ 0 0 0 -1/2 1] + sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) + sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) + sage: Lambda = P.fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: alpha = v.root_lattice().simple_roots() + sage: Matrix([[v._inner_pq(Lambda[i],alpha[j]) for j in v._index_set] for i in v._index_set]) + [ 1 0 0] + [ 0 1/3 0] + [ 0 0 1] """ mcp = pelt.monomial_coefficients() mcq = qelt.monomial_coefficients() zero = ZZ.zero() return sum(mcp.get(i, zero) * mcq[i] / self._eps[i] for i in mcq) + def _inner_pp(self, pelt1, pelt2): + """ + Symmetric form between an two elements of the weight lattice. + + EXAMPLES:: + + sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) + sage: Lambda = P.fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: alpha = v.root_lattice().simple_roots() + sage: Matrix([[v._inner_pp(Lambda[i],P(alpha[j])) for j in v._index_set] for i in v._index_set]) + [ 1 0 0] + [ 0 1/3 0] + [ 0 0 1] + sage: Matrix([[v._inner_pp(Lambda[i],Lambda[j]) for j in v._index_set] for i in v._index_set]) + [ 0 0 0] + [ 0 2/3 1] + [ 0 1 2] + + """ + mc1 = pelt1.monomial_coefficients() + mc2 = pelt2.monomial_coefficients() + return sum(mc1.get(i,0)*self._ac[i]*mc2.get('delta',0) for i in self._index_set) +\ + sum(mc2.get(i,0)*self._ac[i]*mc1.get('delta',0) for i in self._index_set) +\ + sum(mc1.get(i,0)*mc2.get(j,0)*self._ip[i-1][j-1] for i in self._index_set_classical for j in self._index_set_classical) + def to_weight(self, n): """ Return the weight associated to the tuple ``n``. @@ -373,8 +437,7 @@ def freudenthal_roots_imaginary(self, nu): roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. """ l = self._from_weight_helper(nu) - a = self._cartan_type.a() - kp = min(floor(l[i] / a[i]) for i in self._index_set) + kp = min(floor(l[i] / self._a[i]) for i in self._index_set) delta = self._Q.null_root() return [u*delta for u in range(1, kp+1)] From bd45a13e765e767e5d22bde176fae17d32dc693d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 16:24:43 -0400 Subject: [PATCH 246/665] 11111: trivial doctest update --- src/sage/combinat/root_system/hecke_algebra_representation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index a351567ef7d..2e675681ea1 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -79,7 +79,7 @@ def __init__(self, domain, on_basis, cartan_type, q1, q2, q=1, side="right"): sage: domain = W.algebra(QQ) sage: action = lambda x,i: domain.monomial(x.apply_simple_reflection(i, side="right")) sage: HeckeAlgebraRepresentation(domain, action, CartanType(["A",2]), 1, -1) - A representation of the (1, -1)-Hecke algebra of type ['A', 2] on Symmetric group algebra over Rational Field + A representation of the (1, -1)-Hecke algebra of type ['A', 2] on Symmetric group algebra of order 3 over Rational Field """ self._domain = domain self._Ti_on_basis = on_basis From 198d290fbcf0654863dfebd5b00bd422c94cee40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 14 Apr 2015 16:32:05 -0400 Subject: [PATCH 247/665] 11111: ModulesWithBasis.ParentMethods.quotient -> quotient_module --- .../categories/finite_dimensional_algebras_with_basis.py | 2 +- src/sage/categories/modules_with_basis.py | 4 ++-- src/sage/combinat/free_module.py | 2 -- src/sage/modules/with_basis/subquotient.py | 6 +++--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6c2cfa3b6dd..91cf45638b9 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -308,7 +308,7 @@ def semisimple_quotient(self): """ ring = self.base_ring() category = Algebras(ring).WithBasis().FiniteDimensional().Quotients().Semisimple() - result = self.quotient(self.radical(), category=category) + result = self.quotient_module(self.radical(), category=category) result.rename("Semisimple quotient of {}".format(self)) return result diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 971bbf5bc9b..f13a8e07d4a 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -707,7 +707,7 @@ def submodule(self, gens, check=False, already_echelonized=False, category=None) from sage.modules.with_basis.subquotient import SubModuleWithBasis return SubModuleWithBasis(gens, ambient=self, category=category) - def quotient(self, submodule, check=False, already_echelonized=False, category=None): + def quotient_module(self, submodule, check=False, already_echelonized=False, category=None): r""" Construct the quotient free module ``self``/``submodule`` @@ -727,7 +727,7 @@ def quotient(self, submodule, check=False, already_echelonized=False, category=N sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: Y = X.quotient([x[0]-x[1], x[1]-x[2]], already_echelonized=True) + 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() diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 8bd14347edf..50dda7422f4 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -2101,8 +2101,6 @@ def echelon_form(self, elements, base_ring=None): mat.echelonize() return [self.from_vector(vec) for vec in mat if vec != 0] - quotient = ModulesWithBasis.ParentMethods.__dict__["quotient"] - class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 2289aacc7af..cc6df1ad1ca 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -82,7 +82,7 @@ def ambient(self): EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() - sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])) + sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])) sage: Y.ambient() is X True """ @@ -99,7 +99,7 @@ def lift(self, x): EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() - sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.lift(y[2]) x[2] """ @@ -117,7 +117,7 @@ def retract(self, x): EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() - sage: Y = X.quotient((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.print_options(prefix='y') sage: Y.retract(x[0]) y[2] From 6ced308a68c1e9fe271e2dcc94fc3af6ab2eb2cf Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 17:32:42 -0400 Subject: [PATCH 248/665] changed doc tests with odd negatives in fractions --- src/sage/combinat/sf/macdonald.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 6d56d1130d6..c2e35247cfa 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -965,9 +965,9 @@ def nabla(self, q=None, t=None, power=1): sage: H(0).nabla() 0 sage: H([2,2,1]).nabla(t=1/H.t) - q^2/t^4*McdH[2, 2, 1] + ((-q^2)/(-t^4))*McdH[2, 2, 1] sage: H([2,2,1]).nabla(t=1/H.t,power=-1) - t^4/q^2*McdH[2, 2, 1] + ((-t^4)/(-q^2))*McdH[2, 2, 1] """ parent = self.parent() if (q is None and t is None): From 2f8b6ba847064347fb58f0ff1e57217a4bcc05af Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Tue, 14 Apr 2015 23:53:34 +0200 Subject: [PATCH 249/665] review of binary_tree.py changes --- src/sage/combinat/binary_tree.py | 29 +++++++++++++++++++--------- src/sage/combinat/interval_posets.py | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 4e0dc035b86..72e09294b5c 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1982,17 +1982,20 @@ def single_edge_cut_shapes(self): a list of triples `(m, i, n)` of integers - This is a list running over all inner edges of the binary - tree. The removal of each inner edge defines two binary trees, - the root-tree and the sub-tree. - - Here `m` is the node number of the root-tree `R`, `n` the node - number of the sub-tree `S`. The integer `i` is the index of - the leaf of `R` on which `S` was grafted. The leaves of `R` are - numbered starting from `1`, hence `1 leq i \leq m+1`. + This is a list running over all inner edges (i.e., edges + joining two non-leaf vertices) of the binary tree. The removal + of each inner edge defines two binary trees (connected + components), the root-tree and the sub-tree. Thus, to every + inner edge, we can assign three positive integers: + `m` is the node number of the root-tree `R`, and `n` is + the node number of the sub-tree `S`. The integer `i` is the + index of the leaf of `R` on which `S` is grafted to obtain the + original tree. The leaves of `R` are numbered starting from + `1` (from left to right), hence `1 \leq i \leq m+1`. In fact, each of `m` and `n` determines the other, as the - total node number is the node number of ``self``. + total node number of `R` and `S` is the node number of + ``self``. EXAMPLES:: @@ -2003,6 +2006,14 @@ def single_edge_cut_shapes(self): [(2, 1, 1), (2, 3, 1)], [(2, 2, 1), (1, 1, 2)], [(2, 1, 1), (1, 1, 2)]] + + sage: BT = BinaryTrees(2) + sage: [t.single_edge_cut_shapes() for t in BT] + [[(1, 2, 1)], [(1, 1, 1)]] + + sage: BT = BinaryTrees(1) + sage: [t.single_edge_cut_shapes() for t in BT] + [[]] """ resu = [] left, right = list(self) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index f565c422ec9..13af75b20f7 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -1926,7 +1926,7 @@ def maximal_chain_dyck_words(self): def tamari_inversions(self): r""" Return the Tamari inversions of ``self``. A Tamari inversion is - a pair of vertices `(a,b)' with `a < b` such that: + a pair of vertices `(a,b)` with `a < b` such that: - the decreasing parent of `b` is strictly smaller than `a` (or does not exist), and From b6bad1b52fd4661a42c1bab46a01c50b35ba8104 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 14 Apr 2015 18:01:48 -0400 Subject: [PATCH 250/665] corrections to the docstring, delete the cache for H --- src/sage/combinat/sf/macdonald.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index c2e35247cfa..336c8c55ba1 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -69,10 +69,6 @@ _j_to_s_cache = {} _s_to_j_cache = {} -#H basis cache -_h_to_s_cache = {} -_s_to_h_cache = {} - #Ht basis cache _ht_to_m_cache = {} @@ -1249,6 +1245,11 @@ def _m_to_self( self, f ): is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading coefficient of the expansion of ``f`` in the `H_\mu` basis is equal to the leading coefficient of `c_\mu^{-1} f[X(1-t)]`. + + If `t=1`, we must appeal to another triangularity since ``Ht`` is (usually) + still a basis, however `H_\mu[X(1-t)]=0`. In this case we assume that + it is a basis and `H_\mu[X(q-1)]` is `c_\mu m_{\mu'}` plus terms which + are lower in dominance order. INPUT: @@ -1424,7 +1425,8 @@ def _m_to_self( self, f ): If `t=1`, we must appeal to another triangularity since ``Ht`` is (usually) still a basis, however `{\tilde H}_\mu[X(t-1)]=0`. In this case we assume that - it is a basis and + it is a basis and `{\tilde H}_\mu[X(q-1)]` is `c_\mu m_{\mu'}` plus terms which + are lower in dominance order. INPUT: From 3338a9f56bd71e364f7bbc6f024f73c44db39b14 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Tue, 14 Apr 2015 19:07:33 -0700 Subject: [PATCH 251/665] avoid using symmetric_form in __init__ --- src/sage/combinat/root_system/integrable_representations.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index d668a325f96..e8b45115709 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -174,9 +174,7 @@ def __init__(self, Lam): self._ddict = {} self._mdict = {tuple(0 for i in self._index_set): 1} - - Lam_rho = self._Lam + self._P.rho() - self._den0 = Lam_rho.symmetric_form(Lam_rho) + self._rho = self._P.rho() # Coerce a classical root into Q from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) @@ -190,6 +188,7 @@ def __init__(self, Lam): self._ac = self._cartan_type.dual().a() E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical]) self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse() + self._den0 = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho) def highest_weight(self): """ From c1af81eda567082e8ad5a4167b6c45b26f4534be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 01:11:44 -0400 Subject: [PATCH 252/665] 11111: SubModule -> Submodule --- src/sage/categories/modules_with_basis.py | 8 ++++---- src/sage/modules/with_basis/subquotient.py | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index f13a8e07d4a..a64cc70137a 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -704,8 +704,8 @@ def submodule(self, gens, check=False, already_echelonized=False, category=None) """ if not already_echelonized: gens = self.echelonize(gens) - from sage.modules.with_basis.subquotient import SubModuleWithBasis - return SubModuleWithBasis(gens, ambient=self, category=category) + from sage.modules.with_basis.subquotient import SubmoduleWithBasis + return SubmoduleWithBasis(gens, ambient=self, category=category) def quotient_module(self, submodule, check=False, already_echelonized=False, category=None): r""" @@ -738,8 +738,8 @@ def quotient_module(self, submodule, check=False, already_echelonized=False, cat sage: Y.retract(x[0]+2*x[1]) 3*y[2] """ - from sage.modules.with_basis.subquotient import SubModuleWithBasis, QuotientModuleWithBasis - if not isinstance(submodule, SubModuleWithBasis): + from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + if not isinstance(submodule, SubmoduleWithBasis): submodule = self.submodule(submodule, check=check, already_echelonized=already_echelonized) return QuotientModuleWithBasis(submodule, category=category) diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index cc6df1ad1ca..9df44b6d8c0 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -22,7 +22,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): - ``submodule`` -- a submodule - ``category`` -- a category (default: ``ModulesWithBasis(submodule.base_ring())``) - ``submodule`` is typically :class:`SubModuleWithBasis` + ``submodule`` is typically :class:`SubmoduleWithBasis` # FIXME: The following currently works only if: # - The ambient space is finite dimensional @@ -129,7 +129,7 @@ def retract(self, x): return self._from_dict(self._normal(x)._monomial_coefficients) -class SubModuleWithBasis(CombinatorialFreeModule): +class SubmoduleWithBasis(CombinatorialFreeModule): r""" A base class for submodules of a ModuleWithBasis spanned by a (possibly infinite) basis in echelon form. @@ -142,10 +142,10 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts TESTS:: - sage: from sage.modules.with_basis.subquotient import SubModuleWithBasis + 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]), X) + sage: Y2 = SubmoduleWithBasis([x[0]-x[1], x[1]-x[2]], X) sage: Y1 is Y2 True """ @@ -154,17 +154,17 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts ambient = basis.an_element().parent() default_category=ModulesWithBasis(ambient.category().base_ring()).Subobjects() category = default_category.or_subcategory(category, join=True) - return super(SubModuleWithBasis, cls).__classcall__( + return super(SubmoduleWithBasis, cls).__classcall__( cls, basis, ambient, category, *args, **opts) def __init__(self, basis, ambient, category): r""" TESTS:: - sage: from sage.modules.with_basis.subquotient import SubModuleWithBasis + sage: from sage.modules.with_basis.subquotient import SubmoduleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() sage: ybas = (x[0]-x[1], x[1]-x[2]) - sage: Y = SubModuleWithBasis(ybas, X) + sage: Y = SubmoduleWithBasis(ybas, X) sage: Y.basis().list() [B[0], B[1]] sage: [ y.lift() for y in Y.basis() ] @@ -261,7 +261,7 @@ def is_submodule(self, other): """ if other is self.ambient(): return True - if not isinstance(self, SubModuleWithBasis) and self.ambient() is other.ambient(): + if not isinstance(self, SubmoduleWithBasis) and self.ambient() is other.ambient(): raise ValueError("other (=%s) should be a submodule of the same ambient space"%other) if not self in ModulesWithBasis.FiniteDimensional: raise NotImplementedError("is_submodule for infinite dimensional modules") From 1488133505811c7feb1e6dd9e5458709caa9515d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 01:28:32 -0400 Subject: [PATCH 253/665] 11111: standardized the API of SubmoduleWithBasis / QuotientModuleWithBasis + minor doc improvement --- src/sage/categories/modules_with_basis.py | 15 +++++-- src/sage/modules/with_basis/subquotient.py | 47 ++++++++++++++++------ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index a64cc70137a..afdb6d462f2 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -713,9 +713,18 @@ def quotient_module(self, submodule, check=False, already_echelonized=False, cat INPUT: - - ``submodule`` -- a free submodule of ``self``, or something that can - be turned into one via ``self.submodule(submodule)``. - - ``check``, ``already_echelonized`` -- passed down to :meth:`submodule`, which see + - ``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:`submodule`, which see. + + + This # FIXME: The following currently works only if: + # - The ambient space is finite dimensional + # - The embedding is unitriangular + TODO: polish .. WARNING:: diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 9df44b6d8c0..62ed6587711 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -19,15 +19,14 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): INPUT: - - ``submodule`` -- a submodule + - ``submodule`` -- a submodule of ``self`` - ``category`` -- a category (default: ``ModulesWithBasis(submodule.base_ring())``) - ``submodule`` is typically :class:`SubmoduleWithBasis` - - # FIXME: The following currently works only if: - # - The ambient space is finite dimensional - # - The embedding is unitriangular - TODO: polish + ``submodule`` is typically a :class:`SubmoduleWithBasis`. It + should implement a method ``reduce``, and it's ``lift`` method + should have a method ``.cokernel_basis_indices`` that compute the + indexing set of a subset of the basis of ``self`` that spans some + suplementary of ``submodule`` in the ambient space. """ @staticmethod def __classcall_private__(cls, submodule, category=None): @@ -68,8 +67,6 @@ def __init__(self, submodule, category): self._submodule = submodule self._ambient = submodule.ambient() embedding = submodule.lift - # Morphism that computes normal forms module submodule - self._normal = embedding.cokernel_projection() indices = embedding.cokernel_basis_indices() CombinatorialFreeModule.__init__(self, submodule.base_ring(), indices, @@ -126,7 +123,7 @@ def retract(self, x): sage: Y.retract(x[2]) y[2] """ - return self._from_dict(self._normal(x)._monomial_coefficients) + return self._from_dict(self._submodule.reduce(x)._monomial_coefficients) class SubmoduleWithBasis(CombinatorialFreeModule): @@ -215,6 +212,32 @@ def lift(self): triangular="lower", cmp=self.ambient().get_order_cmp(), inverse_on_support="compute") + @lazy_attribute + def reduce(self): + r""" + The reduce map. + + This map reduces elements of the ambient space modulo this + submodule. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) + sage: Y.reduce + Generic endomorphism of Free module generated by {0, 1, 2} over Rational Field + sage: Y.reduce(x[1]) + B[2] + sage: Y.reduce(2*x[0] + x[1]) + 3*B[2] + + TESTS:: + + sage: all( Y.reduce(u.lift()) == 0 for u in Y.basis() ) + True + """ + return self.lift.cokernel_projection() + @lazy_attribute def retract(self): r""" @@ -223,7 +246,7 @@ def retract(self): EXAMPLES:: sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() - sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() + sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) sage: Y.retract Generic morphism: From: Free module generated by {0, 1, 2} over Rational Field @@ -233,7 +256,7 @@ def retract(self): TESTS:: - sage: all( Y.retract(u.lift()) == u for u in y ) + sage: all( Y.retract(u.lift()) == u for u in Y.basis() ) True """ return self.lift.section() From 0b5ab6ba2b645cbbb08053422e7a920e9dcc00ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 01:32:36 -0400 Subject: [PATCH 254/665] 11111: default value for .submodule(check=) + minor doc improvement --- src/sage/categories/modules_with_basis.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index afdb6d462f2..c69d98d1ab6 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -592,7 +592,8 @@ def echelonize(self, gens): mat = matrix([g.to_vector() for g in gens]) return [self.from_vector(v) for v in mat.row_space().basis()] - def submodule(self, gens, check=False, already_echelonized=False, category=None): + def submodule(self, gens, + check=True, already_echelonized=False, category=None): r""" The submodule spanned by a finite set of elements. @@ -650,19 +651,20 @@ def submodule(self, gens, check=False, already_echelonized=False, category=None) sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") sage: x = X.basis() - sage: gens = Family({1 : x[0] - x[1], 2: x[1] - x[2]}); gens + sage: gens = Family({1 : x[0] - x[1], 3: x[1] - x[2]}); gens + Finite family {1: x[0] - x[1], 3: x[1] - x[2]} sage: Y = X.submodule(gens, already_echelonized=True) sage: Y.print_options(prefix='y'); Y - Free module generated by {1, 2} over Rational Field + Free module generated by {1, 3} over Rational Field sage: y = Y.basis() sage: y[1] y[1] sage: y[1].lift() x[0] - x[1] - sage: y[2].lift() + sage: y[3].lift() x[1] - x[2] sage: Y.retract(x[0]-x[2]) - y[1] + y[2] + y[1] + y[3] sage: Y.retract(x[0]) Traceback (most recent call last): ... @@ -707,7 +709,7 @@ def submodule(self, gens, check=False, already_echelonized=False, category=None) from sage.modules.with_basis.subquotient import SubmoduleWithBasis return SubmoduleWithBasis(gens, ambient=self, category=category) - def quotient_module(self, submodule, check=False, already_echelonized=False, category=None): + def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): r""" Construct the quotient free module ``self``/``submodule`` From 54b0865d4837861321e3cb9dacf5fc648a2ebfe5 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 15 Apr 2015 11:38:54 +0200 Subject: [PATCH 255/665] trac #17464: A wrong labelling was returned --- src/sage/combinat/designs/incidence_structures.py | 4 +++- src/sage/graphs/bliss.pyx | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 29ca48a7fb3..d1c2209df2c 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1496,7 +1496,9 @@ def automorphism_group(self): sage: G.is_isomorphic(PGL(3,2)) True sage: G - Permutation Group with generators [(2,3)(4,5), (2,4)(3,5), (1,2)(4,6), (0,1)(4,5)] + Permutation Group with generators [...] + sage: G.cardinality() + 168 A non self-dual example:: diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 114da31612b..f12d8600796 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -253,11 +253,20 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): sage: g = digraphs.RandomTournament(40) # optional - bliss sage: g.is_isomorphic(canonical_form(g,return_graph=True)) # optional - bliss True + + sage: g1 = graphs.RandomGNP(100,.4) # optional - bliss + sage: r = Permutations(range(100)).random_element() # optional - bliss + sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(labels=False)]) # optional - bliss + sage: g1 = canonical_form(g1,return_graph=True) # optional - bliss + sage: g2 = canonical_form(g2,return_graph=True) # optional - bliss + sage: g2 == g2 # optional - bliss + True """ cdef const unsigned int *aut cdef Graph *g = NULL cdef Digraph *d = NULL cdef Stats s + cdef dict relabel vert2int = {} @@ -266,6 +275,7 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): aut = d.canonical_form(s, empty_hook, NULL) edges = [(aut[ vert2int[x] ], aut[ vert2int[y] ]) for x,y in G.edges(labels=False)] + relabel = {v:aut[vert2int[v]] for v in G} del d else: g = bliss_graph(G, partition, vert2int, {}) @@ -274,6 +284,7 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): for x,y in G.edges(labels=False): e,f = aut[ vert2int[x] ], aut[ vert2int[y] ] edges.append( (e,f) if e > f else (f,e)) + relabel = {v:aut[vert2int[v]] for v in G} del g if return_graph: @@ -285,9 +296,9 @@ def canonical_form(G, partition=None, return_graph=False, certify=False): G = Graph(edges,loops=G.allows_loops(),multiedges=G.allows_multiple_edges()) G.add_vertices(vert2int.values()) - return (G, vert2int) if certify else G + return (G, relabel) if certify else G if certify: - return sorted(edges),vert2int + return sorted(edges),relabel return sorted(edges) From 6f4dbfaeadc99751489890f3d351564f94593230 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 10 Apr 2015 09:52:51 +0200 Subject: [PATCH 256/665] trac #18185: Code simplifications (and fix) --- src/sage/graphs/digraph.py | 33 ++++++++++----------------------- src/sage/graphs/graph.py | 26 +++++++------------------- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index f7749d256e4..e3505676926 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -898,33 +898,20 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'DiGraph': self.name(data.name()) elif format == 'rule': - verts = list(verts) - for u in xrange(num_verts): - for v in xrange(num_verts): - uu,vv = verts[u], verts[v] - if f(uu,vv): - self._backend.add_edge(uu,vv,None,True) + self.add_edges((u,v) for u in verts for v in verts if f(u,v)) elif format == 'dict_of_dicts': if convert_empty_dict_labels_to_None: - for u in data: - for v in data[u]: - if multiedges: - for l in data[u][v]: - self._backend.add_edge(u,v,l,True) - else: - self._backend.add_edge(u,v,data[u][v] if data[u][v] != {} else None,True) + r = lambda x:None if x=={} else x else: - for u in data: - for v in data[u]: - if multiedges: - for l in data[u][v]: - self._backend.add_edge(u,v,l,True) - else: - self._backend.add_edge(u,v,data[u][v],True) + r = lambda x:x + + if multiedges: + self.add_edges((u,v,r(l)) for u,Nu in data.iteritems() for v,labels in Nu.iteritems() for l in labels) + else: + self.add_edges((u,v,r(l)) for u,Nu in data.iteritems() for v,l in Nu.iteritems()) + elif format == 'dict_of_lists': - for u in data: - for v in data[u]: - self._backend.add_edge(u,v,None,True) + self.add_edges((u,v) for u,Nu in data.iteritems() for v in Nu) elif format == "list_of_edges": self.allow_multiple_edges(False if multiedges is False else True) self.allow_loops(False if loops is False else True) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 2b92d65ed91..60ed010ad76 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1281,17 +1281,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, multiedges = ( len(set(positions)) < total ) num_verts = data.nrows() elif format == 'Graph': - if loops is None: loops = data.allows_loops() - elif not loops and data.has_loops(): - raise ValueError("The graph was built with loops=False but input data has a loop") + if loops is None: loops = data.allows_loops() if multiedges is None: multiedges = data.allows_multiple_edges() - elif not multiedges: - e = data.edges(labels=False) - e = [sorted(f) for f in e] - if len(e) != len(set(e)): - raise ValueError("No multiple edges but input graph"+ - " has multiple edges.") - if weighted is None: weighted = data.weighted() + if weighted is None: weighted = data.weighted() num_verts = data.num_verts() verts = data.vertex_iterator() if data.get_pos() is not None: @@ -1485,12 +1477,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.name(data.name()) elif format == 'rule': - verts = list(verts) - for u in xrange(num_verts): - for v in xrange(u+1): - uu,vv = verts[u], verts[v] - if f(uu,vv): - self._backend.add_edge(uu,vv,None,False) + from itertools import combinations + self.add_edges(e for e in combinations(verts,2) if f(*e)) + self.add_edges((v,v) for v in verts if f(v,v)) elif format == 'dict_of_dicts': if convert_empty_dict_labels_to_None: @@ -4974,12 +4963,11 @@ def topological_minor(self, H, vertices = False, paths = False, solver=None, ver We say that a graph `G` has a topological `H`-minor (or that it has a graph isomorphic to `H` as a topological minor), if - `G` contains a subdivision of a graph isomorphic to `H` (= + `G` contains a subdivision of a graph isomorphic to `H` (i.e. obtained from `H` through arbitrary subdivision of its edges) as a subgraph. - For more information, see the `Wikipedia article on graph minor - :wikipedia:`Minor_(graph_theory)`. + For more information, see the :wikipedia:`Minor_(graph_theory)`. INPUT: From b03266d885055d56e0b7ae5382df76296aea3ba8 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 11 Apr 2015 18:42:04 +0200 Subject: [PATCH 257/665] trac #18185: Rename graph6-related functions (+doc) --- src/sage/graphs/digraph.py | 6 +- src/sage/graphs/digraph_generators.py | 6 +- src/sage/graphs/generic_graph_pyx.pyx | 141 ++++++++++++++++---------- src/sage/graphs/graph.py | 18 ++-- src/sage/graphs/graph_database.py | 4 +- 5 files changed, 102 insertions(+), 73 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index e3505676926..4c92ef86657 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -638,8 +638,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if n == -1: n = len(data) ss = data[:n] - n, s = generic_graph_pyx.N_inverse(ss) - m = generic_graph_pyx.D_inverse(s, n) + n, s = generic_graph_pyx.length_and_string_from_graph6(ss) + m = generic_graph_pyx.binary_string_from_dig6(s, n) expected = n**2 if len(m) > expected: raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too long."%(ss,n)) @@ -966,7 +966,7 @@ def dig6_string(self): elif self.has_multiple_edges(): raise ValueError('dig6 format does not support multiple edges.') else: - return generic_graph_pyx.N(n) + generic_graph_pyx.R(self._bit_vector()) + return generic_graph_pyx.small_integer_to_graph6(n) + generic_graph_pyx.binary_string_to_graph6(self._bit_vector()) ### Attributes diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index e2dbaac1d7f..6b607016f32 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -273,14 +273,14 @@ def ButterflyGraph(self, n, vertices='strings'): if vertices=='strings': if n>=31: raise NotImplementedError("vertices='strings' is only valid for n<=30.") - from sage.graphs.generic_graph_pyx import binary + from sage.graphs.generic_graph_pyx import int_to_binary_string butterfly = {} for v in xrange(2**n): for i in range(n): w = v w ^= (1 << i) # push 1 to the left by i and xor with w - bv = binary(v) - bw = binary(w) + bv = int_to_binary_string(v) + bw = int_to_binary_string(w) # pad and reverse the strings padded_bv = ('0'*(n-len(bv))+bv)[::-1] padded_bw = ('0'*(n-len(bw))+bw)[::-1] diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 7ba71c128ea..272cb3cc4be 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -307,16 +307,20 @@ cdef run_spring(int iterations, int dim, double* pos, int* edges, int n, bint he sage_free(disp) -def binary(n, length=None): +def int_to_binary_string(n): """ A quick python int to binary string conversion. + INPUT: + + - ``n`` (integer) + EXAMPLE: - sage: sage.graphs.generic_graph_pyx.binary(389) + sage: sage.graphs.generic_graph_pyx.int_to_binary_string(389) '110000101' sage: Integer(389).binary() '110000101' - sage: sage.graphs.generic_graph_pyx.binary(2007) + sage: sage.graphs.generic_graph_pyx.int_to_binary_string(2007) '11111010111' """ cdef mpz_t i @@ -328,71 +332,85 @@ def binary(n, length=None): mpz_clear(i) return t -def R(x): - """ - A helper function for the graph6 format. Described in [McK] +def binary_string_to_graph6(x): + r""" + Transforms a binary string into its graph6 representation. + + This helper function is named `R` in [McK]_. + + INPUT: + + - ``x`` -- a binary string. EXAMPLE: - sage: from sage.graphs.generic_graph_pyx import R - sage: R('110111010110110010111000001100000001000000001') + sage: from sage.graphs.generic_graph_pyx import binary_string_to_graph6 + sage: binary_string_to_graph6('110111010110110010111000001100000001000000001') 'vUqwK@?G' - REFERENCES: - McKay, Brendan. 'Description of graph6 and sparse6 encodings.' - http://cs.anu.edu.au/~bdm/data/formats.txt (2007-02-13) + REFERENCES:: + + .. [McK] McKay, Brendan. 'Description of graph6 and sparse6 encodings.' + http://cs.anu.edu.au/~bdm/data/formats.txt (2007-02-13) """ - # pad on the right to make a multiple of 6 + # The length of x must be a multiple of 6. We extend it with 0s. x += '0' * ( (6 - (len(x) % 6)) % 6) - # split into groups of 6, and convert numbers to decimal, adding 63 + # Split into groups of 6, and convert numbers to decimal, adding 63 six_bits = '' cdef int i for i from 0 <= i < len(x)/6: six_bits += chr( int( x[6*i:6*(i+1)], 2) + 63 ) return six_bits -def N(n): - """ - A helper function for the graph6 format. Described in [McK] +def small_integer_to_graph6(n): + r""" + Encodes a small integer (i.e. a number of vertices) as a graph6 string. - EXAMPLE: - sage: from sage.graphs.generic_graph_pyx import N - sage: N(13) + This helper function is named `N` [McK]_. + + INPUT: + + - ``n`` (integer) + + EXAMPLE:: + + sage: from sage.graphs.generic_graph_pyx import small_integer_to_graph6 + sage: small_integer_to_graph6(13) 'L' - sage: N(136) + sage: small_integer_to_graph6(136) '~?AG' - - REFERENCES: - McKay, Brendan. 'Description of graph6 and sparse6 encodings.' - http://cs.anu.edu.au/~bdm/data/formats.txt (2007-02-13) """ if n < 63: return chr(n + 63) else: # get 18-bit rep of n - n = binary(n) + n = int_to_binary_string(n) n = '0'*(18-len(n)) + n - return chr(126) + R(n) + return chr(126) + binary_string_to_graph6(n) -def N_inverse(s): - """ - A helper function for the graph6 format. Described in [McK] +def length_and_string_from_graph6(s): + r""" + Returns a pair `(length,graph6_string)` from a graph6 string of unknown length. - EXAMPLE: - sage: from sage.graphs.generic_graph_pyx import N_inverse - sage: N_inverse('~??~?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?') + This helper function is the inverse of `N` from [McK]_. + + INPUT: + + - ``s`` -- a graph6 string describing an binary vector (and encoding its + length). + + EXAMPLE:: + + sage: from sage.graphs.generic_graph_pyx import length_and_string_from_graph6 + sage: length_and_string_from_graph6('~??~?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?') (63, '?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?') - sage: N_inverse('_???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????') + sage: length_and_string_from_graph6('_???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????') (32, '???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????') - - REFERENCES: - McKay, Brendan. 'Description of graph6 and sparse6 encodings.' - http://cs.anu.edu.au/~bdm/data/formats.txt (2007-02-13) """ if s[0] == chr(126): # first four bytes are N - a = binary(ord(s[1]) - 63).zfill(6) - b = binary(ord(s[2]) - 63).zfill(6) - c = binary(ord(s[3]) - 63).zfill(6) + a = int_to_binary_string(ord(s[1]) - 63).zfill(6) + b = int_to_binary_string(ord(s[2]) - 63).zfill(6) + c = int_to_binary_string(ord(s[3]) - 63).zfill(6) n = int(a + b + c,2) s = s[4:] else: # only first byte is N @@ -403,19 +421,24 @@ def N_inverse(s): s = s[1:] return n, s -def R_inverse(s, n): - """ - A helper function for the graph6 format. Described in [McK] +def binary_string_from_graph6(s, n): + r""" + Decodes a binary string from its graph6 representation - REFERENCES: - McKay, Brendan. 'Description of graph6 and sparse6 encodings.' - http://cs.anu.edu.au/~bdm/data/formats.txt (2007-02-13) + This helper function is the inverse of `R` from [McK]_. - EXAMPLE: - sage: from sage.graphs.generic_graph_pyx import R_inverse - sage: R_inverse('?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?', 63) + INPUT: + + - ``s`` -- a graph6 string + + - ``n`` -- the length of the binary string encoded by ``s``. + + EXAMPLE:: + + sage: from sage.graphs.generic_graph_pyx import binary_string_from_graph6 + sage: binary_string_from_graph6('?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?', 63) '0000000000000000000000000000001000000000010000000001000010000000000000000000110000000000000000010100000010000000000001000000000010000000000...10000000000000000000000000000000010000000001011011000000100000000001001110000000000000000000000000001000010010000001100000001000000001000000000100000000' - sage: R_inverse('???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????', 32) + sage: binary_string_from_graph6('???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????', 32) '0000000000000000000001000000000000010000100000100000001000000000000000100000000100000...010000000000000100010000001000000000000000000000000000001010000000001011000000000000010010000000000000010000000000100000000001000001000000000000000001000000000000000000000000000000000000' """ @@ -425,20 +448,26 @@ def R_inverse(s, n): o = ord(s[i]) if o > 126 or o < 63: raise RuntimeError("The string seems corrupt: valid characters are \n" + ''.join([chr(i) for i in xrange(63,127)])) - a = binary(o-63) + a = int_to_binary_string(o-63) l.append( '0'*(6-len(a)) + a ) m = "".join(l) return m -def D_inverse(s, n): +def binary_string_from_dig6(s, n): """ A helper function for the dig6 format. + INPUT: + + - ``s`` -- a graph6 string + + - ``n`` -- the length of the binary string encoded by ``s``. + EXAMPLE: - sage: from sage.graphs.generic_graph_pyx import D_inverse - sage: D_inverse('?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?', 63) + sage: from sage.graphs.generic_graph_pyx import binary_string_from_dig6 + sage: binary_string_from_dig6('?????_@?CG??B??@OG?C?G???GO??W@a???CO???OACC?OA?P@G??O??????G??C????c?G?CC?_?@???C_??_?C????PO?C_??AA?OOAHCA___?CC?A?CAOGO??????A??G?GR?C?_o`???g???A_C?OG??O?G_IA????_QO@EG???O??C?_?C@?G???@?_??AC?AO?a???O?????A?_Dw?H???__O@AAOAACd?_C??G?G@??GO?_???O@?_O??W??@P???AG??B?????G??GG???A??@?aC_G@A??O??_?A?????O@Z?_@M????GQ@_G@?C?', 63) '0000000000000000000000000000001000000000010000000001000010000000000000000000110000000000000000010100000010000000000001000000000010000000000...10000000000000000000000000000000010000000001011011000000100000000001001110000000000000000000000000001000010010000001100000001000000001000000000100000000' - sage: D_inverse('???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????', 32) + sage: binary_string_from_dig6('???C?@AA?_?A?O?C??S??O?q_?P?CHD??@?C?GC???C??GG?C_??O?COG????I?J??Q??O?_@@??@??????', 32) '0000000000000000000001000000000000010000100000100000001000000000000000100000000100000...010000000000000100010000001000000000000000000000000000001010000000001011000000000000010010000000000000010000000000100000000001000001000000000000000001000000000000000000000000000000000000' """ @@ -448,7 +477,7 @@ def D_inverse(s, n): o = ord(s[i]) if o > 126 or o < 63: raise RuntimeError("The string seems corrupt: valid characters are \n" + ''.join([chr(i) for i in xrange(63,127)])) - a = binary(o-63) + a = int_to_binary_string(o-63) l.append( '0'*(6-len(a)) + a ) m = "".join(l) return m[:n*n] diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 60ed010ad76..2374bcca2db 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1157,8 +1157,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if n == -1: n = len(data) ss = data[:n] - n, s = generic_graph_pyx.N_inverse(ss) - m = generic_graph_pyx.R_inverse(s, n) + n, s = generic_graph_pyx.length_and_string_from_graph6(ss) + m = generic_graph_pyx.binary_string_from_graph6(s, n) expected = n*(n-1)/2 + (6 - n*(n-1)/2)%6 if len(m) > expected: raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too long."%(ss,n)) @@ -1175,7 +1175,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if n == -1: n = len(data) s = data[:n] - n, s = generic_graph_pyx.N_inverse(s[1:]) + n, s = generic_graph_pyx.length_and_string_from_graph6(s[1:]) if n == 0: edges = [] else: @@ -1183,7 +1183,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, ords = [ord(i) for i in s] if any(o > 126 or o < 63 for o in ords): raise RuntimeError("The string seems corrupt: valid characters are \n" + ''.join([chr(i) for i in xrange(63,127)])) - bits = ''.join([generic_graph_pyx.binary(o-63).zfill(6) for o in ords]) + bits = ''.join([generic_graph_pyx.int_to_binary_string(o-63).zfill(6) for o in ords]) b = [] x = [] for i in xrange(int(floor(len(bits)/(k+1)))): @@ -1587,7 +1587,7 @@ def graph6_string(self): elif self.has_loops() or self.has_multiple_edges(): raise ValueError('graph6 format supports only simple graphs (no loops, no multiple edges)') else: - return generic_graph_pyx.N(n) + generic_graph_pyx.R(self._bit_vector()) + return generic_graph_pyx.small_integer_to_graph6(n) + generic_graph_pyx.binary_string_to_graph6(self._bit_vector()) def sparse6_string(self): """ @@ -1638,18 +1638,18 @@ def sparse6_string(self): s = '' while m < len(edges): if edges[m][1] > v + 1: - sp = generic_graph_pyx.binary(edges[m][1]) + sp = generic_graph_pyx.int_to_binary_string(edges[m][1]) sp = '0'*(k-len(sp)) + sp s += '1' + sp v = edges[m][1] elif edges[m][1] == v + 1: - sp = generic_graph_pyx.binary(edges[m][0]) + sp = generic_graph_pyx.int_to_binary_string(edges[m][0]) sp = '0'*(k-len(sp)) + sp s += '1' + sp v += 1 m += 1 else: - sp = generic_graph_pyx.binary(edges[m][0]) + sp = generic_graph_pyx.int_to_binary_string(edges[m][0]) sp = '0'*(k-len(sp)) + sp s += '0' + sp m += 1 @@ -1662,7 +1662,7 @@ def sparse6_string(self): six_bits = '' for i in range(len(s)//6): six_bits += chr( int( s[6*i:6*(i+1)], 2) + 63 ) - return ':' + generic_graph_pyx.N(n) + six_bits + return ':' + generic_graph_pyx.small_integer_to_graph6(n) + six_bits ### Attributes diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index c6889ab9fc7..8032ae5e39c 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -89,8 +89,8 @@ def data_to_degseq(data, graph6=None): degseq = Integer(data).digits(10) if not degseq: # compute number of 0's in list from graph6 string - from sage.graphs.generic_graph_pyx import N_inverse - return N_inverse(str(graph6))[0]*[0] + from sage.graphs.generic_graph_pyx import length_and_string_from_graph6 + return length_and_string_from_graph6(str(graph6))[0]*[0] else: return degseq From b9cfde3642e3b32abc5c0e67560ec6e4a564c942 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 13 Apr 2015 17:12:59 +0200 Subject: [PATCH 258/665] trac #18185: Move backend creation to the beginning of Graph.__init__ (does not pass tests) --- src/sage/graphs/graph.py | 120 +++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 2374bcca2db..fdcc8b1a28c 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1081,6 +1081,66 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "'data_structure'. Please do not define both.") data_structure = "dense" + if implementation == 'networkx': + import networkx + from sage.graphs.base.graph_backends import NetworkXGraphBackend + if format == 'Graph': + self._backend = NetworkXGraphBackend(data.networkx_graph()) + self._weighted = weighted + self.allow_loops(loops) + self.allow_multiple_edges(multiedges) + else: + if multiedges: + self._backend = NetworkXGraphBackend(networkx.MultiGraph()) + else: + self._backend = NetworkXGraphBackend(networkx.Graph()) + self._weighted = weighted + self.allow_loops(loops) + self.allow_multiple_edges(multiedges) + if verts is not None: + self.add_vertices(verts) + else: + self.add_vertices(range(num_verts)) + elif implementation == 'c_graph': + if multiedges or weighted: + if data_structure == "dense": + raise RuntimeError("Multiedge and weighted c_graphs must be sparse.") + + if immutable: + data_structure = 'static_sparse' + + # If the data structure is static_sparse, we first build a graph + # using the sparse data structure, then reencode the resulting graph + # as a static sparse graph. + from sage.graphs.base.sparse_graph import SparseGraphBackend + from sage.graphs.base.dense_graph import DenseGraphBackend + if data_structure in ["sparse", "static_sparse"]: + CGB = SparseGraphBackend + elif data_structure == "dense": + CGB = DenseGraphBackend + else: + raise ValueError("data_structure must be equal to 'sparse', " + "'static_sparse' or 'dense'") + if format == 'Graph': + self._backend = CGB(0, directed=False) + self.add_vertices(verts) + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + for u,v,l in data.edge_iterator(): + self._backend.add_edge(u,v,l,False) + else: + if verts is not None: + self._backend = CGB(0, directed=False) + self.add_vertices(verts) + else: + self._backend = CGB(num_verts, directed=False) + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + else: + raise NotImplementedError("Supported implementations: networkx, c_graph.") + if format is None and isinstance(data, str): if data.startswith(">>graph6<<"): data = data[10:] @@ -1383,66 +1443,6 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # # From now on, we actually build the graph - if implementation == 'networkx': - import networkx - from sage.graphs.base.graph_backends import NetworkXGraphBackend - if format == 'Graph': - self._backend = NetworkXGraphBackend(data.networkx_graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - else: - if multiedges: - self._backend = NetworkXGraphBackend(networkx.MultiGraph()) - else: - self._backend = NetworkXGraphBackend(networkx.Graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - if verts is not None: - self.add_vertices(verts) - else: - self.add_vertices(range(num_verts)) - elif implementation == 'c_graph': - if multiedges or weighted: - if data_structure == "dense": - raise RuntimeError("Multiedge and weighted c_graphs must be sparse.") - - if immutable: - data_structure = 'static_sparse' - - # If the data structure is static_sparse, we first build a graph - # using the sparse data structure, then reencode the resulting graph - # as a static sparse graph. - from sage.graphs.base.sparse_graph import SparseGraphBackend - from sage.graphs.base.dense_graph import DenseGraphBackend - if data_structure in ["sparse", "static_sparse"]: - CGB = SparseGraphBackend - elif data_structure == "dense": - CGB = DenseGraphBackend - else: - raise ValueError("data_structure must be equal to 'sparse', " - "'static_sparse' or 'dense'") - if format == 'Graph': - self._backend = CGB(0, directed=False) - self.add_vertices(verts) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - for u,v,l in data.edge_iterator(): - self._backend.add_edge(u,v,l,False) - else: - if verts is not None: - self._backend = CGB(0, directed=False) - self.add_vertices(verts) - else: - self._backend = CGB(num_verts, directed=False) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - else: - raise NotImplementedError("Supported implementations: networkx, c_graph.") - if format == 'graph6': k = 0 for i in xrange(n): From 050b916c1459f94a80b0c78b2331d261919c6717 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 13 Apr 2015 17:54:06 +0200 Subject: [PATCH 259/665] trac #18185: Fix and simplify the code (now tests pass again) --- src/sage/graphs/graph.py | 54 ++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index fdcc8b1a28c..ca5bb0a3652 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1081,31 +1081,16 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "'data_structure'. Please do not define both.") data_structure = "dense" + # Choice of the backend + if implementation == 'networkx': import networkx from sage.graphs.base.graph_backends import NetworkXGraphBackend - if format == 'Graph': - self._backend = NetworkXGraphBackend(data.networkx_graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - else: - if multiedges: - self._backend = NetworkXGraphBackend(networkx.MultiGraph()) - else: - self._backend = NetworkXGraphBackend(networkx.Graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - if verts is not None: - self.add_vertices(verts) - else: - self.add_vertices(range(num_verts)) + self._backend = NetworkXGraphBackend() elif implementation == 'c_graph': if multiedges or weighted: if data_structure == "dense": raise RuntimeError("Multiedge and weighted c_graphs must be sparse.") - if immutable: data_structure = 'static_sparse' @@ -1121,23 +1106,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, else: raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") - if format == 'Graph': - self._backend = CGB(0, directed=False) - self.add_vertices(verts) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - for u,v,l in data.edge_iterator(): - self._backend.add_edge(u,v,l,False) - else: - if verts is not None: - self._backend = CGB(0, directed=False) - self.add_vertices(verts) - else: - self._backend = CGB(num_verts, directed=False) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) + self._backend = CGB(0, directed=False) else: raise NotImplementedError("Supported implementations: networkx, c_graph.") @@ -1433,7 +1402,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = False if multiedges is None: multiedges = False if loops is None: loops = False - if format == 'int': num_verts = data + if format == 'int': + num_verts = data + if num_verts<0: + raise ValueError("The number of vertices cannot be strictly negative!") else: num_verts = len(data) curves = data @@ -1443,6 +1415,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # # From now on, we actually build the graph + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + if verts is not None: + self.add_vertices(verts) + elif num_verts: + self.add_vertices(range(num_verts)) + if format == 'graph6': k = 0 for i in xrange(n): @@ -1475,6 +1455,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'Graph': self.name(data.name()) + self.add_vertices(data.vertices()) + self.add_edges(data.edge_iterator()) elif format == 'rule': from itertools import combinations From d5c08121837e4e87ea597584fd7bdd848c470071 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 13 Apr 2015 17:55:35 +0200 Subject: [PATCH 260/665] trac #18185: Move backend creation to the beginning of DiGraph.__init__ (does not pass tests) --- src/sage/graphs/digraph.py | 117 +++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 4c92ef86657..cc96c103b83 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -571,6 +571,65 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "'data_structure'. Please do not define both.") data_structure = "dense" + + if implementation == 'networkx': + import networkx + from sage.graphs.base.graph_backends import NetworkXGraphBackend + if format == 'DiGraph': + self._backend = NetworkXGraphBackend(data.networkx_graph()) + self._weighted = weighted + self.allow_loops(loops) + self.allow_multiple_edges(multiedges) + else: + self._backend = NetworkXGraphBackend(networkx.MultiDiGraph()) + self._weighted = weighted + self.allow_loops(loops) + self.allow_multiple_edges(multiedges) + if verts is not None: + self.add_vertices(verts) + else: + self.add_vertices(range(num_verts)) + elif implementation == 'c_graph': + if multiedges or weighted: + if data_structure == "dense": + raise RuntimeError("Multiedge and weighted c_graphs must be sparse.") + + if immutable: + data_structure = 'static_sparse' + + # If the data structure is static_sparse, we first build a graph + # using the sparse data structure, then reencode the resulting graph + # as a static sparse graph. + from sage.graphs.base.sparse_graph import SparseGraphBackend + from sage.graphs.base.dense_graph import DenseGraphBackend + if data_structure in ["sparse", "static_sparse"]: + CGB = SparseGraphBackend + elif data_structure == "dense": + CGB = DenseGraphBackend + else: + raise ValueError("data_structure must be equal to 'sparse', " + "'static_sparse' or 'dense'") + if format == 'DiGraph': + self._backend = CGB(0, directed=True) + self.add_vertices(verts) + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + for u,v,l in data.edge_iterator(): + self._backend.add_edge(u,v,l,True) + else: + self._backend = CGB(0, directed=True) + if verts is not None: + self._backend = CGB(0, directed=True) + self.add_vertices(verts) + else: + self._backend = CGB(num_verts, directed=True) + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + else: + raise NotImplementedError("Supported implementations: networkx, c_graph.") + if format is None and isinstance(data, str): format = 'dig6' if data[:8] == ">>dig6<<": @@ -816,64 +875,6 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # weighted, multiedges, loops, verts and num_verts should now be set - if implementation == 'networkx': - import networkx - from sage.graphs.base.graph_backends import NetworkXGraphBackend - if format == 'DiGraph': - self._backend = NetworkXGraphBackend(data.networkx_graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - else: - self._backend = NetworkXGraphBackend(networkx.MultiDiGraph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - if verts is not None: - self.add_vertices(verts) - else: - self.add_vertices(range(num_verts)) - elif implementation == 'c_graph': - if multiedges or weighted: - if data_structure == "dense": - raise RuntimeError("Multiedge and weighted c_graphs must be sparse.") - - if immutable: - data_structure = 'static_sparse' - - # If the data structure is static_sparse, we first build a graph - # using the sparse data structure, then reencode the resulting graph - # as a static sparse graph. - from sage.graphs.base.sparse_graph import SparseGraphBackend - from sage.graphs.base.dense_graph import DenseGraphBackend - if data_structure in ["sparse", "static_sparse"]: - CGB = SparseGraphBackend - elif data_structure == "dense": - CGB = DenseGraphBackend - else: - raise ValueError("data_structure must be equal to 'sparse', " - "'static_sparse' or 'dense'") - if format == 'DiGraph': - self._backend = CGB(0, directed=True) - self.add_vertices(verts) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - for u,v,l in data.edge_iterator(): - self._backend.add_edge(u,v,l,True) - else: - self._backend = CGB(0, directed=True) - if verts is not None: - self._backend = CGB(0, directed=True) - self.add_vertices(verts) - else: - self._backend = CGB(num_verts, directed=True) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - else: - raise NotImplementedError("Supported implementations: networkx, c_graph.") - if format == 'dig6': k = 0 for i in xrange(n): From 313810ef7d807e27004f35584505cdb465b6b06c Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 13 Apr 2015 18:09:54 +0200 Subject: [PATCH 261/665] trac #18185: Fix and simplify the code (now tests pass again) --- src/sage/graphs/digraph.py | 46 ++++++++++---------------------- src/sage/graphs/generic_graph.py | 1 - 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index cc96c103b83..0fd3469b59c 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -571,24 +571,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "'data_structure'. Please do not define both.") data_structure = "dense" + # Choice of the backend if implementation == 'networkx': import networkx from sage.graphs.base.graph_backends import NetworkXGraphBackend - if format == 'DiGraph': - self._backend = NetworkXGraphBackend(data.networkx_graph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - else: - self._backend = NetworkXGraphBackend(networkx.MultiDiGraph()) - self._weighted = weighted - self.allow_loops(loops) - self.allow_multiple_edges(multiedges) - if verts is not None: - self.add_vertices(verts) - else: - self.add_vertices(range(num_verts)) + self._backend = NetworkXGraphBackend(networkx.MultiDiGraph()) elif implementation == 'c_graph': if multiedges or weighted: if data_structure == "dense": @@ -609,24 +597,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, else: raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") - if format == 'DiGraph': - self._backend = CGB(0, directed=True) - self.add_vertices(verts) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - for u,v,l in data.edge_iterator(): - self._backend.add_edge(u,v,l,True) - else: - self._backend = CGB(0, directed=True) - if verts is not None: - self._backend = CGB(0, directed=True) - self.add_vertices(verts) - else: - self._backend = CGB(num_verts, directed=True) - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) + self._backend = CGB(0, directed=True) else: raise NotImplementedError("Supported implementations: networkx, c_graph.") @@ -872,8 +843,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if multiedges is None: multiedges = False if loops is None: loops = False num_verts = data + if num_verts<0: + raise ValueError("The number of vertices cannot be strictly negative!") # weighted, multiedges, loops, verts and num_verts should now be set + self._weighted = weighted + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + if verts is not None: + self.add_vertices(verts) + elif num_verts: + self.add_vertices(range(num_verts)) if format == 'dig6': k = 0 @@ -897,6 +877,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'incidence_matrix': self.add_edges(positions) elif format == 'DiGraph': + self.add_vertices(data.vertices()) + self.add_edges(data.edge_iterator()) self.name(data.name()) elif format == 'rule': self.add_edges((u,v) for u in verts for v in verts if f(u,v)) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a532b970539..65f9288be36 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -449,7 +449,6 @@ def __eq__(self, other): return False if self.weighted() != other.weighted(): return False - verts = self.vertices() # Finally, we are prepared to check edges: if not self.allows_multiple_edges(): From 1f2e0fa1ea8825da328a0fa47e0740c9c1738144 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 14 Apr 2015 11:34:46 +0200 Subject: [PATCH 262/665] trac #18185: Merge the last two sections of the graph constructor --- src/sage/graphs/generic_graph.py | 2 +- src/sage/graphs/graph.py | 280 +++++++++++++++---------------- 2 files changed, 136 insertions(+), 146 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 65f9288be36..4ed9f7137c6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3050,7 +3050,7 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): TESTS:: sage: Graph({'H': ['G','L','L','D'], 'L': ['G','D']}).eulerian_circuit(labels=False) - [('H', 'D'), ('D', 'L'), ('L', 'G'), ('G', 'H'), ('H', 'L'), ('L', 'H')] + [('H', 'L'), ('L', 'H'), ('H', 'G'), ('G', 'L'), ('L', 'D'), ('D', 'H')] sage: Graph({0: [0, 1, 1, 1, 1]}).eulerian_circuit(labels=False) [(0, 1), (1, 0), (0, 1), (1, 0), (0, 0)] """ diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index ca5bb0a3652..d438e4b2742 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1,3 +1,4 @@ + r""" Undirected graphs @@ -982,6 +983,12 @@ class Graph(GenericGraph): sage: {G_imm:1}[H_imm] 1 + TESTS:: + + sage: Graph(4,format="HeyHeyHey") + Traceback (most recent call last): + ... + ValueError: Unknown input format 'HeyHeyHey' """ _directed = False @@ -1168,18 +1175,19 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None: raise ValueError("This input cannot be turned into a graph") - # At this point, format has been set. - - # adjust for empty dicts instead of None in NetworkX default edge labels - if convert_empty_dict_labels_to_None is None: - convert_empty_dict_labels_to_None = (format == 'NX') + if format == 'weighted_adjacency_matrix': + if weighted is False: + raise ValueError("Format was weighted_adjacency_matrix but weighted was False.") + if weighted is None: weighted = True + if multiedges is None: multiedges = False + format = 'adjacency_matrix' - verts = None + # At this point, 'format' has been set. We build the graph if format == 'graph6': - if loops is None: loops = False if weighted is None: weighted = False - if multiedges is None: multiedges = False + self.allow_loops(loops if loops else False, check=False) + self.allow_multiple_edges(multiedges if multiedges else False, check=False) if not isinstance(data, str): raise ValueError('If input format is graph6, then data must be a string.') n = data.find('\n') @@ -1193,11 +1201,18 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too long."%(ss,n)) elif len(m) < expected: raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n)) - num_verts = n + self.add_vertices(range(n)) + k = 0 + for i in xrange(n): + for j in xrange(i): + if m[k] == '1': + self._backend.add_edge(i, j, None, False) + k += 1 + elif format == 'sparse6': - if loops is None: loops = True if weighted is None: weighted = False - if multiedges is None: multiedges = True + self.allow_loops(False if loops is False else True, check=False) + self.allow_multiple_edges(False if multiedges is False else True, check=False) from math import ceil, floor from sage.misc.functional import log n = data.find('\n') @@ -1228,16 +1243,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, else: if v < n: edges.append((x[i],v)) - num_verts = n - elif format in ['adjacency_matrix', 'incidence_matrix']: + self.add_vertices(range(n)) + self.add_edges(edges) + elif format == 'adjacency_matrix': assert is_Matrix(data) - if format == 'weighted_adjacency_matrix': - if weighted is False: - raise ValueError("Format was weighted_adjacency_matrix but weighted was False.") - if weighted is None: weighted = True - if multiedges is None: multiedges = False - format = 'adjacency_matrix' - if format == 'adjacency_matrix': # note: the adjacency matrix might be weighted and hence not # necessarily consists of integers if not weighted and data.base_ring() != ZZ: @@ -1275,9 +1284,25 @@ def __init__(self, data=None, pos=None, loops=None, format=None, loops = True if loops is None: loops = False - - num_verts = data.nrows() + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + self.add_vertices(range(data.nrows())) + e = [] + if weighted: + for i,j in data.nonzero_positions(): + if i <= j: + e.append((i,j,data[i][j])) + elif multiedges: + for i,j in data.nonzero_positions(): + if i <= j: + e += [(i,j)]*int(data[i][j]) + else: + for i,j in data.nonzero_positions(): + if i <= j: + e.append((i,j)) + self.add_edges(e) elif format == 'incidence_matrix': + assert is_Matrix(data) positions = [] for c in data.columns(): NZ = c.nonzero_positions() @@ -1303,29 +1328,63 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if L != desirable: msg += "Each column represents an edge: -1 goes to 1." raise ValueError(msg) - if loops is None: loops = False if weighted is None: weighted = False if multiedges is None: total = len(positions) multiedges = ( len(set(positions)) < total ) - num_verts = data.nrows() + self.allow_loops(loops if loops else False, check=False) + self.allow_multiple_edges(multiedges, check=False) + self.add_vertices(range(data.nrows())) + self.add_edges(positions) elif format == 'Graph': if loops is None: loops = data.allows_loops() if multiedges is None: multiedges = data.allows_multiple_edges() if weighted is None: weighted = data.weighted() - num_verts = data.num_verts() - verts = data.vertex_iterator() + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) if data.get_pos() is not None: pos = data.get_pos().copy() - + self.name(data.name()) + self.add_vertices(data.vertices()) + self.add_edges(data.edge_iterator()) + elif format == 'NX' + if convert_empty_dict_labels_to_None is not False: + r = lambda x:None if x=={} else x + else: + r = lambda x:x + if weighted is None: + if isinstance(data, networkx.Graph): + weighted = False + if multiedges is None: + multiedges = False + if loops is None: + loops = False + else: + weighted = True + if multiedges is None: + multiedges = True + if loops is None: + loops = True + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) + self.add_vertices(data.nodes()) + self.add_edges((u,v,r(l)) for u,v,l in data.edges_iter(data=True)) elif format == 'rule': f = data[1] - if loops is None: loops = any(f(v,v) for v in data[0]) - if multiedges is None: multiedges = False - if weighted is None: weighted = False - num_verts = len(data[0]) verts = data[0] + if loops is None: loops = any(f(v,v) for v in verts) + if weighted is None: weighted = False + self.allow_loops(loops, check=False) + self.allow_multiple_edges(True if multiedges else False, check=False) + from itertools import combinations + self.add_vertices(verts) + self.add_edges(e for e in combinations(verts,2) if f(*e)) + self.add_edges((v,v) for v in verts if f(v,v)) elif format == 'dict_of_dicts': + # adjust for empty dicts instead of None in NetworkX default edge labels + if convert_empty_dict_labels_to_None is None: + convert_empty_dict_labels_to_None = (format == 'NX') + if not all(isinstance(data[u], dict) for u in data): raise ValueError("Input dict must be a consistent format.") @@ -1351,9 +1410,28 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise ValueError("Dict of dicts for multigraph must be in the format {v : {u : list}}") if multiedges is None and len(data) > 0: multiedges = True - + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) verts = set().union(data.keys(), *data.values()) - num_verts = len(verts) + self.add_vertices(verts) + if convert_empty_dict_labels_to_None: + for u in data: + for v in data[u]: + if hash(u) <= hash(v) or v not in data or u not in data[v]: + if multiedges: + for l in data[u][v]: + self._backend.add_edge(u,v,l,False) + else: + self._backend.add_edge(u,v,data[u][v] if data[u][v] != {} else None,False) + else: + for u in data: + for v in data[u]: + if hash(u) <= hash(v) or v not in data or u not in data[v]: + if multiedges: + for l in data[u][v]: + self._backend.add_edge(u,v,l,False) + else: + self._backend.add_edge(u,v,data[u][v],False) elif format == 'dict_of_lists': if not all(isinstance(data[u], list) for u in data): raise ValueError("Input dict must be a consistent format.") @@ -1379,121 +1457,30 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if multiedges is None: multiedges = True if multiedges is None: multiedges = False - num_verts = len(verts) - elif format == 'NX': - if weighted is None: - if isinstance(data, networkx.Graph): - weighted = False - if multiedges is None: - multiedges = False - if loops is None: - loops = False - else: - weighted = True - if multiedges is None: - multiedges = True - if loops is None: - loops = True - num_verts = data.order() - verts = data.nodes() - data = data.adj - format = 'dict_of_dicts' - elif format in ['int', 'elliptic_curve_congruence']: - if weighted is None: weighted = False - if multiedges is None: multiedges = False - if loops is None: loops = False - if format == 'int': - num_verts = data - if num_verts<0: - raise ValueError("The number of vertices cannot be strictly negative!") - else: - num_verts = len(data) - curves = data - verts = [curve.cremona_label() for curve in data] - - # weighted, multiedges, loops, verts and num_verts should now be set - # - # From now on, we actually build the graph - - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - if verts is not None: + self.allow_loops(loops, check=False) + self.allow_multiple_edges(multiedges, check=False) self.add_vertices(verts) - elif num_verts: - self.add_vertices(range(num_verts)) - - if format == 'graph6': - k = 0 - for i in xrange(n): - for j in xrange(i): - if m[k] == '1': - self._backend.add_edge(i, j, None, False) - k += 1 - - elif format == 'sparse6': - self.add_edges(edges) - - elif format == 'adjacency_matrix': - e = [] - if weighted: - for i,j in data.nonzero_positions(): - if i <= j: - e.append((i,j,data[i][j])) - elif multiedges: - for i,j in data.nonzero_positions(): - if i <= j: - e += [(i,j)]*int(data[i][j]) - else: - for i,j in data.nonzero_positions(): - if i <= j: - e.append((i,j)) - self.add_edges(e) - - elif format == 'incidence_matrix': - self.add_edges(positions) - - elif format == 'Graph': - self.name(data.name()) - self.add_vertices(data.vertices()) - self.add_edges(data.edge_iterator()) - - elif format == 'rule': - from itertools import combinations - self.add_edges(e for e in combinations(verts,2) if f(*e)) - self.add_edges((v,v) for v in verts if f(v,v)) - - elif format == 'dict_of_dicts': - if convert_empty_dict_labels_to_None: - for u in data: - for v in data[u]: - if hash(u) <= hash(v) or v not in data or u not in data[v]: - if multiedges: - for l in data[u][v]: - self._backend.add_edge(u,v,l,False) - else: - self._backend.add_edge(u,v,data[u][v] if data[u][v] != {} else None,False) - else: - for u in data: - for v in data[u]: - if hash(u) <= hash(v) or v not in data or u not in data[v]: - if multiedges: - for l in data[u][v]: - self._backend.add_edge(u,v,l,False) - else: - self._backend.add_edge(u,v,data[u][v],False) - - elif format == 'dict_of_lists': for u in data: for v in data[u]: if (multiedges or hash(u) <= hash(v) or v not in data or u not in data[v]): self._backend.add_edge(u,v,None,False) - + elif format == 'int': + self.allow_loops(loops if loops else False, check=False) + self.allow_multiple_edges(multiedges if multiedges else False, check=False) + if data<0: + raise ValueError("The number of vertices cannot be strictly negative!") + if data: + self.add_vertices(range(data)) elif format == 'elliptic_curve_congruence': + self.allow_loops(loops if loops else False, check=False) + self.allow_multiple_edges(multiedges if multiedges else False, check=False) from sage.rings.arith import lcm, prime_divisors from sage.rings.fast_arith import prime_range from sage.misc.all import prod + curves = data + verts = [curve.cremona_label() for curve in data] + self.add_vertices(verts) for i in xrange(self.order()): for j in xrange(i): E = curves[i] @@ -1514,9 +1501,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, p_edges = [p for p in p_edges if p in P] if len(p_edges) > 0: self._backend.add_edge(E.cremona_label(), F.cremona_label(), str(p_edges)[1:-1], False) - elif format == "list_of_edges": - self.allow_multiple_edges(False if multiedges is False else True) - self.allow_loops(False if loops is False else True) + + elif format == 'list_of_edges': + self.allow_multiple_edges(False if multiedges is False else True, check=False) + self.allow_loops(False if loops is False else True, check=False) self.add_edges(data) if multiedges is not True and self.has_multiple_edges(): deprecation(15706, "You created a graph with multiple edges " @@ -1524,7 +1512,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "when you do so, as in the future the default " "behaviour will be to ignore those edges") elif multiedges is None: - self.allow_multiple_edges(False) + self.allow_multiple_edges(False, check=False) if loops is not True and self.has_loops(): deprecation(15706, "You created a graph with loops from a list. "+ @@ -1532,10 +1520,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, "the future the default behaviour will be to ignore "+ "those edges") elif loops is None: - self.allow_loops(False) - + self.allow_loops(False, check=False) else: - assert format == 'int' + raise ValueError("Unknown input format '{}'".format(format)) + + if weighted is None: weighted = False + self._weighted = weighted self._pos = pos self._boundary = boundary if boundary is not None else [] From 4b15f0f7f1cebd6f858e49ae2bf952dec6a2544f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 15 Apr 2015 12:44:05 +0200 Subject: [PATCH 263/665] trac #18185: Merge the last two sections of the DiGraph constructor --- src/sage/graphs/digraph.py | 176 ++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 90 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 0fd3469b59c..c3d035ee0e2 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -560,6 +560,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, 1 sage: copy(g) is g # copy is mutable again False + + TESTS:: + + sage: DiGraph(4,format="HeyHeyHey") + Traceback (most recent call last): + ... + ValueError: Unknown input format 'HeyHeyHey' """ msg = '' GenericGraph.__init__(self) @@ -647,21 +654,20 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = False num_verts=0 + if format == 'weighted_adjacency_matrix': + if weighted is False: + raise ValueError("Format was weighted_adjacency_matrix but weighted was False.") + if weighted is None: weighted = True + if multiedges is None: multiedges = False + format = 'adjacency_matrix' + if format is None: raise ValueError("This input cannot be turned into a graph") - # At this point, format has been set. - - # adjust for empty dicts instead of None in NetworkX default edge labels - if convert_empty_dict_labels_to_None is None: - convert_empty_dict_labels_to_None = (format == 'NX') - - verts = None + # At this point, format has been set. We build the graph if format == 'dig6': - if loops is None: loops = False if weighted is None: weighted = False - if multiedges is None: multiedges = False if not isinstance(data, str): raise ValueError('If input format is dig6, then data must be a string.') n = data.find('\n') @@ -675,16 +681,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too long."%(ss,n)) elif len(m) < expected: raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n)) - num_verts = n - elif format in ['adjacency_matrix', 'incidence_matrix']: + self.allow_loops(True if loops else False,check=False) + self.allow_multiple_edges(True if multiedges else False,check=False) + self.add_vertices(range(n)) + k = 0 + for i in xrange(n): + for j in xrange(n): + if m[k] == '1': + self._backend.add_edge(i, j, None, True) + k += 1 + elif format == 'adjacency_matrix': assert is_Matrix(data) - if format == 'weighted_adjacency_matrix': - if weighted is False: - raise ValueError("Format was weighted_adjacency_matrix but weighted was False.") - if weighted is None: weighted = True - if multiedges is None: multiedges = False - format = 'adjacency_matrix' - if format == 'adjacency_matrix': # note: the adjacency matrix might be weighted and hence not # necessarily consists of integers if not weighted and data.base_ring() != ZZ: @@ -720,11 +727,22 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise ValueError("Non-looped digraph's adjacency"+ " matrix must have zeroes on the diagonal.") loops = True - if loops is None: - loops = False - - num_verts = data.nrows() + self.allow_multiple_edges(multiedges,check=False) + self.allow_loops(True if loops else False,check=False) + self.add_vertices(range(data.nrows())) + e = [] + if weighted: + for i,j in data.nonzero_positions(): + e.append((i,j,data[i][j])) + elif multiedges: + for i,j in data.nonzero_positions(): + e += [(i,j)]*int(data[i][j]) + else: + for i,j in data.nonzero_positions(): + e.append((i,j)) + self.add_edges(e) elif format == 'incidence_matrix': + assert is_Matrix(data) positions = [] for c in data.columns(): NZ = c.nonzero_positions() @@ -739,12 +757,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, positions.append(tuple(NZ)) else: positions.append((NZ[1],NZ[0])) - if loops is None: loops = False if weighted is None: weighted = False if multiedges is None: total = len(positions) multiedges = ( len(set(positions)) < total ) - num_verts = data.nrows() + self.allow_loops(True if loops else False,check=False) + self.allow_multiple_edges(multiedges,check=False) + self.add_vertices(range(data.nrows())) + self.add_edges(positions) elif format == 'DiGraph': if loops is None: loops = data.allows_loops() elif not loops and data.has_loops(): @@ -755,18 +775,22 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if len(e) != len(set(e)): raise ValueError("No multiple edges but input digraph"+ " has multiple edges.") + self.allow_multiple_edges(multiedges,check=False) + self.allow_loops(loops,check=False) if weighted is None: weighted = data.weighted() - num_verts = data.num_verts() - verts = data.vertex_iterator() if data.get_pos() is not None: pos = data.get_pos().copy() + self.add_vertices(data.vertices()) + self.add_edges(data.edge_iterator()) + self.name(data.name()) elif format == 'rule': f = data[1] if loops is None: loops = any(f(v,v) for v in data[0]) - if multiedges is None: multiedges = False if weighted is None: weighted = False - num_verts = len(data[0]) - verts = data[0] + self.allow_multiple_edges(True if multiedges else False,check=False) + self.allow_loops(loops,check=False) + self.add_vertices(data[0]) + self.add_edges((u,v) for u in data[0] for v in data[0] if f(u,v)) elif format == 'dict_of_dicts': if not all(isinstance(data[u], dict) for u in data): raise ValueError("Input dict must be a consistent format.") @@ -793,8 +817,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, raise ValueError("Dict of dicts for multidigraph must be in the format {v : {u : list}}") if multiedges is None and len(data) > 0: multiedges = True + self.allow_multiple_edges(multiedges,check=False) + self.allow_loops(loops,check=False) + self.add_vertices(verts) - num_verts = len(verts) + if multiedges: + self.add_edges((u,v,l) for u,Nu in data.iteritems() for v,labels in Nu.iteritems() for l in labels) + else: + self.add_edges((u,v,l) for u,Nu in data.iteritems() for v,l in Nu.iteritems()) elif format == 'dict_of_lists': # convert to a dict of lists if not already one if not all(isinstance(data[u], list) for u in data): @@ -817,10 +847,16 @@ def __init__(self, data=None, pos=None, loops=None, format=None, multiedges = True if multiedges is None: multiedges = False - + self.allow_multiple_edges(multiedges,check=False) + self.allow_loops(loops,check=False) verts = set().union(data.keys(),*data.values()) - num_verts = len(verts) + self.add_vertices(verts) + self.add_edges((u,v) for u,Nu in data.iteritems() for v in Nu) elif format == 'NX': + # adjust for empty dicts instead of None in NetworkX default edge labels + if convert_empty_dict_labels_to_None is None: + convert_empty_dict_labels_to_None = (format == 'NX') + if weighted is None: if isinstance(data, networkx.DiGraph): weighted = False @@ -834,68 +870,24 @@ def __init__(self, data=None, pos=None, loops=None, format=None, multiedges = data.multiedges if loops is None: loops = data.selfloops - num_verts = data.order() - verts = data.nodes() - data = data.adj - format = 'dict_of_dicts' - elif format == 'int': - if weighted is None: weighted = False - if multiedges is None: multiedges = False - if loops is None: loops = False - num_verts = data - if num_verts<0: - raise ValueError("The number of vertices cannot be strictly negative!") - - # weighted, multiedges, loops, verts and num_verts should now be set - self._weighted = weighted - self.allow_loops(loops, check=False) - self.allow_multiple_edges(multiedges, check=False) - if verts is not None: - self.add_vertices(verts) - elif num_verts: - self.add_vertices(range(num_verts)) - - if format == 'dig6': - k = 0 - for i in xrange(n): - for j in xrange(n): - if m[k] == '1': - self._backend.add_edge(i, j, None, True) - k += 1 - elif format == 'adjacency_matrix': - e = [] - if weighted: - for i,j in data.nonzero_positions(): - e.append((i,j,data[i][j])) - elif multiedges: - for i,j in data.nonzero_positions(): - e += [(i,j)]*int(data[i][j]) - else: - for i,j in data.nonzero_positions(): - e.append((i,j)) - self.add_edges(e) - elif format == 'incidence_matrix': - self.add_edges(positions) - elif format == 'DiGraph': - self.add_vertices(data.vertices()) - self.add_edges(data.edge_iterator()) - self.name(data.name()) - elif format == 'rule': - self.add_edges((u,v) for u in verts for v in verts if f(u,v)) - elif format == 'dict_of_dicts': if convert_empty_dict_labels_to_None: r = lambda x:None if x=={} else x else: r = lambda x:x - if multiedges: - self.add_edges((u,v,r(l)) for u,Nu in data.iteritems() for v,labels in Nu.iteritems() for l in labels) - else: - self.add_edges((u,v,r(l)) for u,Nu in data.iteritems() for v,l in Nu.iteritems()) - - elif format == 'dict_of_lists': - self.add_edges((u,v) for u,Nu in data.iteritems() for v in Nu) - elif format == "list_of_edges": + self.allow_multiple_edges(multiedges,check=False) + self.allow_loops(loops,check=False) + self.add_vertices(data.nodes()) + self.add_edges((u,v,r(l)) for u,v,l in data.edges_iter(data=True)) + elif format == 'int': + if weighted is None: weighted = False + self.allow_loops(True if loops else False,check=False) + self.allow_multiple_edges(True if multiedges else False,check=False) + if data<0: + raise ValueError("The number of vertices cannot be strictly negative!") + elif data: + self.add_vertices(range(data)) + elif format == 'list_of_edges': self.allow_multiple_edges(False if multiedges is False else True) self.allow_loops(False if loops is False else True) self.add_edges(data) @@ -915,7 +907,11 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif loops is None: self.allow_loops(False) else: - assert format == 'int' + raise ValueError("Unknown input format '{}'".format(format)) + + # weighted, multiedges, loops, verts and num_verts should now be set + self._weighted = weighted + self._pos = pos self._boundary = boundary if boundary is not None else [] if format != 'DiGraph' or name is not None: From 599e0632bfb79e9e119dd306ea2fbd50dc039dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 15 Apr 2015 14:11:59 +0200 Subject: [PATCH 264/665] trac #18162 reviewer commit : step one plot3d --- src/doc/en/reference/plot3d/index.rst | 2 +- src/sage/plot/plot3d/implicit_surface.pyx | 15 ++++++---- src/sage/plot/plot3d/shapes.pyx | 35 +++++++++-------------- src/sage/plot/plot3d/transform.pyx | 2 +- src/sage/plot/plot3d/tri_plot.py | 6 ++-- 5 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/doc/en/reference/plot3d/index.rst b/src/doc/en/reference/plot3d/index.rst index 1855ae433ce..3358a838cff 100644 --- a/src/doc/en/reference/plot3d/index.rst +++ b/src/doc/en/reference/plot3d/index.rst @@ -19,13 +19,13 @@ sage/plot/plot3d/texture sage/plot/plot3d/index_face_set - sage/plot/plot3d/help sage/plot/plot3d/implicit_surface sage/plot/plot3d/shapes sage/plot/plot3d/transform sage/plot/plot3d/tri_plot .. broken, see #16647 +.. sage/plot/plot3d/help .. sage/plot/java3d .. include:: ../footer.txt diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index bf4c8c0f9e8..843f848fbfd 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -180,11 +180,13 @@ cdef class MarchingCubes: Protocol: 1. Create the class. - 2. Call process_slice once for each X slice, from self.nx > x >= 0. - 3. Call finish(), which returns a list of strings. + 2. Call ``process_slice`` once for each X slice, from self.nx > x >= 0. + 3. Call ``finish()``, which returns a list of strings. - Note: Actually, only 4 slices ever exist; the caller will re-use old - storage. + .. NOTE:: + + Actually, only 4 slices ever exist; the caller will re-use old + storage. """ cdef readonly object xrange @@ -336,7 +338,8 @@ cdef class MarchingCubesTriangles(MarchingCubes): def process_slice(self, unsigned int x, np.ndarray slice): """ - Process a single slice of function evaluations at the specified x coordinate. + Process a single slice of function evaluations at the specified `x` + coordinate. EXAMPLES:: @@ -1152,7 +1155,7 @@ cdef class ImplicitSurface(IndexFaceSet): Note that if you call this method more than once, subsequent invocations will have no effect (this is an optimization to - avoid repeated work) unless you specify force=True in the + avoid repeated work) unless you specify ``force=True`` in the keywords. EXAMPLES:: diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 72b31fec644..f6054d18f51 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -211,11 +211,11 @@ cdef class Cone(ParametricSurface): INPUT: - - ``radius`` - positive real number + - ``radius`` -- positive real number - - ``height`` - positive real number + - ``height`` -- positive real number - - ``closed`` - whether or not to include the base (default True) + - ``closed`` -- whether or not to include the base (default ``True``) - ``**kwds`` -- passed to the ParametricSurface constructor @@ -303,11 +303,11 @@ cdef class Cylinder(ParametricSurface): INPUT: - - ``radius`` - positive real number + - ``radius`` -- positive real number - - ``height`` - positive real number + - ``height`` -- positive real number - - ``closed`` - whether or not to include the ends (default True) + - ``closed`` -- whether or not to include the ends (default ``True``) - ``**kwds`` -- passed to the ParametricSurface constructor @@ -520,13 +520,13 @@ def LineSegment(start, end, thickness=1, radius=None, **kwds): sage: from sage.plot.plot3d.shapes import LineSegment, Sphere sage: P = (0,0,0.1) sage: Q = (0.5,0.6,0.7) - sage: S = Sphere(.2, color='red').translate(P) + \ - Sphere(.2, color='blue').translate(Q) + \ - LineSegment(P, Q, .05, color='black') + sage: S = Sphere(.2, color='red').translate(P) + + ....: Sphere(.2, color='blue').translate(Q) + + ....: LineSegment(P, Q, .05, color='black') sage: S.show() - sage: S = Sphere(.1, color='red').translate(P) + \ - Sphere(.1, color='blue').translate(Q) + \ - LineSegment(P, Q, .15, color='black') + sage: S = Sphere(.1, color='red').translate(P) + + ....: Sphere(.1, color='blue').translate(Q) + + ....: LineSegment(P, Q, .15, color='black') sage: S.show() AUTHOR: @@ -593,7 +593,7 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * Graphics3d Object Change the width of the arrow. (Note: for an arrow that scales with zoom, please consider - the 'line3d' function with the option 'arrow_head=True'):: + the ``line3d`` function with the option ``arrow_head=True``):: sage: arrow3d((0,0,0), (1,1,1), width=1) Graphics3d Object @@ -620,13 +620,6 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * sage: a = arrow3d((0,0,0), (0,0,-1)) sage: a.all[0].get_transformation().transform_point((0,0,1)) (0.0, 0.0, -1.0) - - The thickness option is now deprecated. It has been replaced by the width option. :: - - sage: arrow3d((0,0,0), (1,1,1), thickness=1) - doctest:...: DeprecationWarning: use the option 'width' instead of 'thickness' - See http://trac.sagemath.org/7154 for details. - Graphics3d Object """ if radius is None: radius = width/50.0 @@ -756,7 +749,7 @@ cdef class Sphere(ParametricSurface): sage: S.translate(10, 100, 1000).jmol_repr(S.default_render_params()) [['isosurface sphere_1 center {10.0 100.0 1000.0} sphere 2.0\ncolor isosurface [102,102,255]']] - It can't natively handle ellipsoids:: + It cannot natively handle ellipsoids:: sage: Sphere(1).scale(2, 3, 4).jmol_repr(S.testing_render_params()) [['pmesh obj_2 "obj_2.pmesh"\ncolor pmesh [102,102,255]']] diff --git a/src/sage/plot/plot3d/transform.pyx b/src/sage/plot/plot3d/transform.pyx index 027ccb9443d..90dd5ecd4f0 100644 --- a/src/sage/plot/plot3d/transform.pyx +++ b/src/sage/plot/plot3d/transform.pyx @@ -132,7 +132,7 @@ cdef class Transformation: def rotate_arbitrary(v, double theta): """ Return a matrix that rotates the coordinate space about - the axis v by the angle theta. + the axis v by the angle ``theta``. INPUT: diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index 5d670907038..b8baa854676 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -7,10 +7,10 @@ - Joshua Kantor -- Algorithm design - Marshall Hampton -- Docstrings and doctests -TODO: +.. TODO:: -- Parametrizations (cylindrical, spherical) -- Massive optimization + - Parametrizations (cylindrical, spherical) + - Massive optimization """ ########################################################################### From da71ab27b9f58545b4d68e245e9f2fab66e21e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 15 Apr 2015 14:26:23 +0200 Subject: [PATCH 265/665] trac #18162 step two : plot and again plot3d --- src/sage/plot/misc.py | 32 +++++++++++++++++--------------- src/sage/plot/plot3d/shapes.pyx | 4 ++-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index c7a303bb586..51d93086eda 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -26,17 +26,17 @@ def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): INPUT: - - ``funcs`` - a function, or a list, tuple, or vector of functions + - ``funcs`` -- a function, or a list, tuple, or vector of functions - - ``ranges`` - a list of ranges. A range can be a 2-tuple of + - ``ranges`` -- a list of ranges. A range can be a 2-tuple of numbers specifying the minimum and maximum, or a 3-tuple giving the variable explicitly. - - ``plot_points`` - a tuple of integers specifying the number of + - ``plot_points`` -- a tuple of integers specifying the number of plot points for each range. If a single number is specified, it will be the value for all ranges. This defaults to 2. - - ``return_vars`` - (default False) If True, return the variables, + - ``return_vars`` -- (default ``False``) If ``True``, return the variables, in order. @@ -44,14 +44,14 @@ def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): - ``fast_funcs`` - if only one function passed, then a fast - callable function. If funcs is a list or tuple, then a tuple - of fast callable functions is returned. + callable function. If funcs is a list or tuple, then a tuple + of fast callable functions is returned. - ``range_specs`` - a list of range_specs: for each range, a - tuple is returned of the form (range_min, range_max, - range_step) such that ``srange(range_min, range_max, - range_step, include_endpoint=True)`` gives the correct points - for evaluation. + tuple is returned of the form (range_min, range_max, + range_step) such that ``srange(range_min, range_max, + range_step, include_endpoint=True)`` gives the correct points + for evaluation. EXAMPLES:: @@ -152,14 +152,14 @@ def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): def unify_arguments(funcs): """ - Returns a tuple of variables of the functions, as well as the + Return a tuple of variables of the functions, as well as the number of "free" variables (i.e., variables that defined in a callable function). INPUT: - ``funcs`` -- a list of functions; these can be symbolic - expressions, polynomials, etc + expressions, polynomials, etc OUTPUT: functions, expected arguments @@ -167,7 +167,7 @@ def unify_arguments(funcs): - A tuple of variables that were "free" in the functions - EXAMPLES: + EXAMPLES:: sage: x,y,z=var('x,y,z') sage: f(x,y)=x+y-z @@ -252,8 +252,10 @@ def get_matplotlib_linestyle(linestyle, return_type): """ Function which translates between matplotlib linestyle in short notation (i.e. '-', '--', ':', '-.') and long notation (i.e. 'solid', 'dashed', - 'dotted', 'dashdot' ). If linestyle is none of these allowed options the - function raises a ValueError. + 'dotted', 'dashdot' ). + + If linestyle is none of these allowed options, the function raises + a ValueError. INPUT: diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index f6054d18f51..d98e48b3b9e 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -587,7 +587,7 @@ def arrow3d(start, end, width=1, radius=None, head_radius=None, head_len=None, * sage: arrow3d((2,1,0), (1,1,1), color='green', head_radius=0.3, aspect_ratio=[1,1,1]) Graphics3d Object - Many arrow arranged in a circle (flying spears?):: + Many arrows arranged in a circle (flying spears?):: sage: sum([arrow3d((cos(t),sin(t),0),(cos(t),sin(t),1)) for t in [0,0.3,..,2*pi]]) Graphics3d Object @@ -906,7 +906,7 @@ class Text(PrimitiveObject): def obj_repr(self, render_params): """ - The obj file format doesn't support text strings:: + The obj file format does not support text strings:: sage: from sage.plot.plot3d.shapes import Text sage: Text("Hi").obj_repr(None) From f5eef01db304c5277e2330f7829eb622ad224dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 15 Apr 2015 14:37:33 +0200 Subject: [PATCH 266/665] trac #18162 fix broken doctests --- src/sage/plot/plot3d/shapes.pyx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index d98e48b3b9e..13606bbca0f 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -520,13 +520,13 @@ def LineSegment(start, end, thickness=1, radius=None, **kwds): sage: from sage.plot.plot3d.shapes import LineSegment, Sphere sage: P = (0,0,0.1) sage: Q = (0.5,0.6,0.7) - sage: S = Sphere(.2, color='red').translate(P) + - ....: Sphere(.2, color='blue').translate(Q) + - ....: LineSegment(P, Q, .05, color='black') + sage: S = Sphere(.2, color='red').translate(P) + sage: S += Sphere(.2, color='blue').translate(Q) + sage: S += LineSegment(P, Q, .05, color='black') sage: S.show() - sage: S = Sphere(.1, color='red').translate(P) + - ....: Sphere(.1, color='blue').translate(Q) + - ....: LineSegment(P, Q, .15, color='black') + sage: S = Sphere(.1, color='red').translate(P) + sage: S += Sphere(.1, color='blue').translate(Q) + sage: S += LineSegment(P, Q, .15, color='black') sage: S.show() AUTHOR: From 84a6aea2bd6444211319c3266974aac553b40832 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 15 Apr 2015 14:52:16 +0200 Subject: [PATCH 267/665] Deprecate PARI functions --- src/sage/libs/pari/gen.pyx | 279 +++++++++--------- src/sage/libs/pari/pari_instance.pyx | 13 +- src/sage/rings/laurent_series_ring.py | 14 +- src/sage/rings/number_field/totallyreal.pyx | 2 +- .../rings/number_field/totallyreal_rel.py | 2 +- src/sage/tests/benchmark.py | 4 +- 6 files changed, 155 insertions(+), 159 deletions(-) diff --git a/src/sage/libs/pari/gen.pyx b/src/sage/libs/pari/gen.pyx index 6d595a3b323..b64c0def73a 100644 --- a/src/sage/libs/pari/gen.pyx +++ b/src/sage/libs/pari/gen.pyx @@ -54,6 +54,7 @@ import operator import sage.structure.element from sage.structure.element cimport ModuleElement, RingElement, Element from sage.misc.randstate cimport randstate, current_randstate +from sage.misc.superseded import deprecation, deprecated_function_alias include 'pari_err.pxi' include 'sage/ext/stdsage.pxi' @@ -3686,50 +3687,6 @@ cdef class gen(gen_auto): """ return gsizebyte(x.g) - def sizedigit(gen x): - """ - sizedigit(x): Return a quick estimate for the maximal number of - decimal digits before the decimal point of any component of x. - - INPUT: - - - - ``x`` - gen - - - OUTPUT: - - - - ``int`` - Python integer - - - EXAMPLES:: - - sage: x = pari('10^100') - sage: x.Str().length() - 101 - sage: x.sizedigit() - 101 - - Note that digits after the decimal point are ignored. - - :: - - sage: x = pari('1.234') - sage: x - 1.23400000000000 - sage: x.sizedigit() - 1 - - The estimate can be one too big:: - - sage: pari('7234.1').sizedigit() - 4 - sage: pari('9234.1').sizedigit() - 5 - """ - return sizedigit(x.g) - def truncate(gen x, estimate=False): """ truncate(x,estimate=False): Return the truncation of x. If estimate @@ -4175,31 +4132,6 @@ cdef class gen(gen_auto): pari_catch_sig_on() return P.new_gen(bernreal(x, prec_bits_to_words(precision))) - def bernvec(gen x): - r""" - Creates a vector containing, as rational numbers, the Bernoulli - numbers `B_0, B_2,\ldots, B_{2x}`. This routine is - obsolete. Use bernfrac instead each time you need a Bernoulli - number in exact form. - - Note: this routine is implemented using repeated independent calls - to bernfrac, which is faster than the standard recursion in exact - arithmetic. - - EXAMPLES:: - - sage: pari(8).bernvec() - doctest:...: DeprecationWarning: bernvec() is deprecated, use repeated calls to bernfrac() instead - See http://trac.sagemath.org/15767 for details. - [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6, -3617/510] - sage: [pari(2*n).bernfrac() for n in range(9)] - [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6, -3617/510] - """ - from sage.misc.superseded import deprecation - deprecation(15767, 'bernvec() is deprecated, use repeated calls to bernfrac() instead') - pari_catch_sig_on() - return P.new_gen(bernvec(x)) - def besselh1(gen nu, x, unsigned long precision=0): r""" The `H^1`-Bessel function of index `\nu` and @@ -5163,17 +5095,6 @@ cdef class gen(gen_auto): # 4: NUMBER THEORETICAL functions ########################################### - def bezout(gen x, y): - cdef gen u, v, g - cdef GEN U, V, G - cdef gen t0 = objtogen(y) - pari_catch_sig_on() - G = gbezout(x.g, t0.g, &U, &V) - g = P.new_gen_noclear(G) - u = P.new_gen_noclear(U) - v = P.new_gen(V) - return g, u, v - def binomial(gen x, long k): """ binomial(x, k): return the binomial coefficient "x choose k". @@ -5541,17 +5462,6 @@ cdef class gen(gen_auto): pari_catch_sig_on() return P.new_gen(sumdivk(n.g, k)) - def xgcd(gen x, y): - """ - Returns u,v,d such that d=gcd(x,y) and u\*x+v\*y=d. - - EXAMPLES:: - - sage: pari(10).xgcd(15) - (5, -1, 1) - """ - return x.bezout(y) - def Zn_issquare(gen self, n): """ Return ``True`` if ``self`` is a square modulo `n`, ``False`` @@ -5941,31 +5851,6 @@ cdef class gen(gen_auto): set_gel(g, i + 1, ellap(self.g, gel(g, i + 1))) return P.new_gen(g) - def ellbil(self, z0, z1, unsigned long precision=0): - """ - e.ellbil(z0, z1): return the value of the canonical bilinear form - on z0 and z1. - - INPUT: - - - - ``e`` - elliptic curve (assumed integral given by a - minimal model, as returned by ellminimalmodel) - - - ``z0, z1`` - rational points on e - - - EXAMPLES:: - - sage: e = pari([0,1,1,-2,0]).ellinit().ellminimalmodel()[0] - sage: e.ellbil([1, 0], [-1, 1]) - 0.418188984498861 - """ - cdef gen t0 = objtogen(z0) - cdef gen t1 = objtogen(z1) - pari_catch_sig_on() - return P.new_gen(bilhell(self.g, t0.g, t1.g, prec_bits_to_words(precision))) - def ellchangecurve(self, ch): """ e.ellchangecurve(ch): return the new model (equation) for the @@ -6014,9 +5899,10 @@ cdef class gen(gen_auto): pari_catch_sig_on() return P.new_gen(elleta(self.g, prec_bits_to_words(precision))) - def ellheight(self, a, long flag=-1, unsigned long precision=0): + def ellheight(self, a, b=None, long flag=-1, unsigned long precision=0): """ - canonical height of point ``a`` on elliptic curve ``self``. + Canonical height of point ``a`` on elliptic curve ``self``, + resp. the value of the associated bilinear form at ``(a,b)``. INPUT: @@ -6024,6 +5910,8 @@ cdef class gen(gen_auto): - ``a`` -- rational point on ``self``. + - ``b`` -- (optional) rational point on ``self``. + - ``precision (optional)`` -- the precision of the result, in bits. @@ -6035,13 +5923,24 @@ cdef class gen(gen_auto): sage: e.ellheight([1,0], precision=128).sage() 0.47671165934373953737948605888465305945902294218 # 32-bit 0.476711659343739537379486058884653059459022942211150879336 # 64-bit + + Computing the bilinear form:: + + sage: e.ellheight([1, 0], [-1, 1]) + 0.418188984498861 """ if flag != -1: from sage.misc.superseded import deprecation deprecation(16997, 'The flag argument to ellheight() is deprecated and not used anymore') cdef gen t0 = objtogen(a) - pari_catch_sig_on() - return P.new_gen(ellheight(self.g, t0.g, prec_bits_to_words(precision))) + cdef gen t1 + if b is None: + pari_catch_sig_on() + return P.new_gen(ellheight(self.g, t0.g, prec_bits_to_words(precision))) + else: + t1 = objtogen(b) + pari_catch_sig_on() + return P.new_gen(ellheight0(self.g, t0.g, t1.g, prec_bits_to_words(precision))) def ellheightmatrix(self, x, unsigned long precision=0): """ @@ -6428,14 +6327,12 @@ cdef class gen(gen_auto): pari_catch_sig_on() return P.new_gen(zell(self.g, t0.g, prec_bits_to_words(precision))) - def ellpow(self, z, n): + def ellmul(self, z, n): """ - e.ellpow(z, n): return `n` times the point `z` on the elliptic - curve `e`. + Return `n` times the point `z` on the elliptic curve `e`. INPUT: - - ``e`` - elliptic curve - ``z`` - point on `e` @@ -6444,7 +6341,6 @@ cdef class gen(gen_auto): multiplication for `e`. Complex multiplication currently only works if `e` is defined over `Q`. - EXAMPLES: We consider a curve with CM by `Z[i]`:: sage: e = pari([0,0,0,3,0]).ellinit() @@ -6452,16 +6348,16 @@ cdef class gen(gen_auto): Multiplication by two:: - sage: e.ellpow([0,0], 2) + sage: e.ellmul([0,0], 2) [0] - sage: e.ellpow(p, 2) + sage: e.ellmul(p, 2) [1/4, -7/8] Complex multiplication:: - sage: q = e.ellpow(p, 1+I); q + sage: q = e.ellmul(p, 1+I); q [-2*I, 1 + I] - sage: e.ellpow(q, 1-I) + sage: e.ellmul(q, 1-I) [1/4, -7/8] TESTS:: @@ -6482,8 +6378,8 @@ cdef class gen(gen_auto): ....: # Evaluate cm_minpoly(cm)(P), which should be zero ....: # ....: e = pari(E) # Convert E to PARI - ....: P2 = e.ellpow(P, cm_minpoly[2]*cm + cm_minpoly[1]) - ....: P0 = e.elladd(e.ellpow(P, cm_minpoly[0]), e.ellpow(P2, cm)) + ....: P2 = e.ellmul(P, cm_minpoly[2]*cm + cm_minpoly[1]) + ....: P0 = e.elladd(e.ellmul(P, cm_minpoly[0]), e.ellmul(P2, cm)) ....: assert(P0 == E(0)) """ cdef gen t0 = objtogen(z) @@ -8233,11 +8129,7 @@ cdef class gen(gen_auto): pari_catch_sig_on() return P.new_gen(rootpadic(self.g, t0.g, r)) - def polsturm_full(self): - pari_catch_sig_on() - n = sturmpart(self.g, NULL, NULL) - pari_catch_sig_off() - return n + polsturm_full = deprecated_function_alias(18203, gen_auto.polsturm) def serreverse(self): """ @@ -8683,13 +8575,6 @@ cdef class gen(gen_auto): This is the LLL-reduced Z-basis of the kernel of the matrix x with integral entries. - INPUT: - - - - ``flag`` - optional, and may be set to 0: default, - uses a modified LLL, 1: uses matrixqz. - - EXAMPLES:: sage: pari('[2,1;2,1]').matker() @@ -8697,8 +8582,12 @@ cdef class gen(gen_auto): sage: pari('[2,1;2,1]').matkerint() [1; -2] sage: pari('[2,1;2,1]').matkerint(1) + doctest:...: DeprecationWarning: The flag argument to matkerint() is deprecated by PARI + See http://trac.sagemath.org/18203 for details. [1; -2] """ + if flag: + deprecation(18203, "The flag argument to matkerint() is deprecated by PARI") pari_catch_sig_on() return P.new_gen(matkerint0(self.g, flag)) @@ -9417,6 +9306,110 @@ cdef class gen(gen_auto): pari_catch_sig_off() return + #################################################################### + # Functions deprecated by upstream PARI + # + # NOTE: these should remain in Sage as long as PARI supports them, + # do not just delete these methods! + #################################################################### + + def bezout(x, y): + deprecation(18203, "bezout() is deprecated in PARI, use gcdext() instead (note that the output is in a different order!)") + u, v, g = x.gcdext(y) + return g, u, v + + def xgcd(x, y): + """ + Returns u,v,d such that d=gcd(x,y) and u\*x+v\*y=d. + + EXAMPLES:: + + sage: pari(10).xgcd(15) + doctest:...: DeprecationWarning: xgcd() is deprecated, use gcdext() instead (note that the output is in a different order!) + See http://trac.sagemath.org/18203 for details. + (5, -1, 1) + """ + deprecation(18203, "xgcd() is deprecated, use gcdext() instead (note that the output is in a different order!)") + u, v, g = x.gcdext(y) + return g, u, v + + def sizedigit(x): + """ + sizedigit(x): Return a quick estimate for the maximal number of + decimal digits before the decimal point of any component of x. + + INPUT: + + - ``x`` - gen + + OUTPUT: Python integer + + EXAMPLES:: + + sage: x = pari('10^100') + sage: x.Str().length() + 101 + sage: x.sizedigit() + doctest:...: DeprecationWarning: sizedigit() is deprecated in PARI + See http://trac.sagemath.org/18203 for details. + 101 + + Note that digits after the decimal point are ignored:: + + sage: x = pari('1.234') + sage: x + 1.23400000000000 + sage: x.sizedigit() + 1 + + The estimate can be one too big:: + + sage: pari('7234.1').sizedigit() + 4 + sage: pari('9234.1').sizedigit() + 5 + """ + deprecation(18203, "sizedigit() is deprecated in PARI") + return sizedigit(x.g) + + def bernvec(x): + r""" + Creates a vector containing, as rational numbers, the Bernoulli + numbers `B_0, B_2,\ldots, B_{2x}`. This routine is + obsolete. Use bernfrac instead each time you need a Bernoulli + number in exact form. + + Note: this routine is implemented using repeated independent calls + to bernfrac, which is faster than the standard recursion in exact + arithmetic. + + EXAMPLES:: + + sage: pari(8).bernvec() + doctest:...: DeprecationWarning: bernvec() is deprecated, use repeated calls to bernfrac() instead + See http://trac.sagemath.org/15767 for details. + [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6, -3617/510] + sage: [pari(2*n).bernfrac() for n in range(9)] + [1, 1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6, -3617/510] + """ + deprecation(15767, 'bernvec() is deprecated, use repeated calls to bernfrac() instead') + pari_catch_sig_on() + return P.new_gen(bernvec(x)) + + bezoutres = deprecated_function_alias(18203, gen_auto.polresultantext) + + ellbil = deprecated_function_alias(18203, ellheight) + + ellpow = deprecated_function_alias(18203, ellmul) + + def rnfpolred(*args, **kwds): + deprecation(18203, "rnfpolred() is deprecated in PARI, port your code to use rnfpolredbest() instead") + return gen_auto.rnfpolred(*args, **kwds) + + def rnfpolredabs(*args, **kwds): + deprecation(18203, "rnfpolredabs() is deprecated in PARI, port your code to use rnfpolredbest() instead") + return gen_auto.rnfpolredabs(*args, **kwds) + cpdef gen objtogen(s): """ diff --git a/src/sage/libs/pari/pari_instance.pyx b/src/sage/libs/pari/pari_instance.pyx index 15c5e7ec93f..ac434b555b1 100644 --- a/src/sage/libs/pari/pari_instance.pyx +++ b/src/sage/libs/pari/pari_instance.pyx @@ -177,6 +177,7 @@ from sage.libs.flint.fmpz_mat cimport * from sage.libs.pari.gen cimport gen, objtogen from sage.libs.pari.handle_error cimport _pari_init_error_handling +from sage.misc.superseded import deprecated_function_alias # so Galois groups are represented in a sane way # See the polgalois section of the PARI users manual. @@ -1332,23 +1333,25 @@ cdef class PariInstance(PariInstance_auto): pari_catch_sig_on() return self.new_gen(pollegendre(n, self.get_var(v))) - def poltchebi(self, long n, v=-1): + def polchebyshev(self, long n, v=-1): """ - poltchebi(n, v=x): Chebyshev polynomial of the first kind of degree + polchebyshev(n, v=x): Chebyshev polynomial of the first kind of degree n, in variable v. EXAMPLES:: - sage: pari.poltchebi(7) + sage: pari.polchebyshev(7) 64*x^7 - 112*x^5 + 56*x^3 - 7*x - sage: pari.poltchebi(7, 'z') + sage: pari.polchebyshev(7, 'z') 64*z^7 - 112*z^5 + 56*z^3 - 7*z - sage: pari.poltchebi(0) + sage: pari.polchebyshev(0) 1 """ pari_catch_sig_on() return self.new_gen(polchebyshev1(n, self.get_var(v))) + poltchebi = deprecated_function_alias(18203, polchebyshev) + def factorial(self, long n): """ Return the factorial of the integer n as a PARI gen. diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 8d5b757f631..3fe70320178 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -330,19 +330,19 @@ def _element_constructor_(self, x, n=0): See http://trac.sagemath.org/16201 for details. sage: L(pari('1/x')) q^-1 - sage: L(pari('poltchebi(5)')) + sage: L(pari('polchebyshev(5)')) 5*q - 20*q^3 + 16*q^5 - sage: L(pari('poltchebi(5) - 1/x^4')) + sage: L(pari('polchebyshev(5) - 1/x^4')) -q^-4 + 5*q - 20*q^3 + 16*q^5 - sage: L(pari('1/poltchebi(5)')) + sage: L(pari('1/polchebyshev(5)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + O(q^9) - sage: L(pari('poltchebi(5) + O(x^40)')) + sage: L(pari('polchebyshev(5) + O(x^40)')) 5*q - 20*q^3 + 16*q^5 + O(q^40) - sage: L(pari('poltchebi(5) - 1/x^4 + O(x^40)')) + sage: L(pari('polchebyshev(5) - 1/x^4 + O(x^40)')) -q^-4 + 5*q - 20*q^3 + 16*q^5 + O(q^40) - sage: L(pari('1/poltchebi(5) + O(x^10)')) + sage: L(pari('1/polchebyshev(5) + O(x^10)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + 8192/125*q^9 + O(q^10) - sage: L(pari('1/poltchebi(5) + O(x^10)'), -10) # Multiply by q^-10 + sage: L(pari('1/polchebyshev(5) + O(x^10)'), -10) # Multiply by q^-10 1/5*q^-11 + 4/5*q^-9 + 64/25*q^-7 + 192/25*q^-5 + 2816/125*q^-3 + 8192/125*q^-1 + O(1) sage: L(pari('O(x^-10)')) O(q^-10) diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index 420d57c590b..82e877bfd57 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -389,7 +389,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False d_poly = nf.poldisc() counts[0] += 1 - if d_poly > 0 and nf.polsturm_full() == n: + if d_poly > 0 and nf.polsturm() == n: da = int_has_small_square_divisor(Integer(d_poly)) if d_poly > dB or d_poly <= B*da: counts[1] += 1 diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index 267992d921b..a6486210873 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -785,7 +785,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a = [], verbose=0, nf = nf.polresultant(nfF, parit) d = nf.poldisc() #counts[0] += 1 - if d > 0 and nf.polsturm_full() == n: + if d > 0 and nf.polsturm() == n: da = int_has_small_square_divisor(Integer(d)) if d > dB or d <= B*da: counts[1] += 1 diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 420facb168f..62183016f60 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -1563,7 +1563,7 @@ def gp(self): E = gp.ellinit('[0, 0, 1, -1, 0]') gp.eval('gettime') P = gp([0,0]) - Q = E.ellpow(P, self.n) + Q = E.ellmul(P, self.n) return float(gp.eval('gettime/1000.0')) def pari(self): @@ -1580,7 +1580,7 @@ def pari(self): E = pari('ellinit([0, 0, 1, -1, 0])') pari('gettime') P = pari([0,0]) - Q = E.ellpow(P, self.n) + Q = E.ellmul(P, self.n) return float(pari('gettime/1000.0')) class EllipticCurveMW(Benchmark): From 40c709f85d80a15c9be831f0d4b471b60c2f2107 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 11 Mar 2015 10:35:16 +0100 Subject: [PATCH 268/665] trac #17927: Discarded arguments in IntegerVector --- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/integer_vector.py | 29 +++++++++++++++-- .../combinat/integer_vectors_mod_permgroup.py | 32 ++++++++++++------- src/sage/combinat/misc.py | 7 +--- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 53e4b56402c..ed35dbfaad1 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -1187,7 +1187,7 @@ class CombinatorialClass(Parent): """ __metaclass__ = ClasscallMetaclass - def __init__(self, category = None, *keys, **opts): + def __init__(self, category = None): """ TESTS:: diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 85468f110e5..84dfc3a603e 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -507,6 +507,21 @@ def IntegerVectors(n=None, k=None, **kwargs): """ Returns the combinatorial class of (non-negative) integer vectors. + INPUT: + + - `n` -- if set to an integer, returns the combinatorial class of integer + vectors whose sum is `n`. If set to ``None`` (default), no such constraint + is defined. + + - ``k`` -- the length of the vectors. Set to ``None`` (default) if you do + not want such a constraint. + + All other arguments given to this function are forwarded to the instance of + :class:`IntegerVectors_all` :class:`IntegerVectors_nconstraints` + :class:`IntegerVectors_nk` or :class:`IntegerVectors_nkconstraints` that it + returns. + + NOTE - These integer vectors are non-negative. EXAMPLES: If n is not specified, it returns the class of all @@ -614,9 +629,18 @@ def IntegerVectors(n=None, k=None, **kwargs): sage: iv = [ IntegerVectors(x[0], x[1], max_part = x[2]-1) for x in essai ] sage: all(map(lambda x: x.cardinality() == len(x.list()), iv)) True + + TESTS: + + :trac:`17927`:: + + sage: IntegerVectors(None, length=3) + Traceback (most recent call last): + ... + TypeError: __init__() got an unexpected keyword argument 'length' """ if n is None: - return IntegerVectors_all() + return IntegerVectors_all(**kwargs) elif k is None: return IntegerVectors_nconstraints(n, kwargs) elif isinstance(k, builtinlist): @@ -629,7 +653,6 @@ def IntegerVectors(n=None, k=None, **kwargs): else: return IntegerVectors_nk(n,k) - class IntegerVectors_all(CombinatorialClass): def _repr_(self): """ @@ -881,6 +904,7 @@ def rank(self, x): class IntegerVectors_nkconstraints(IntegerListsLex): def __init__(self, n, k, constraints, category=None): + """ EXAMPLES:: @@ -952,7 +976,6 @@ def _repr_(self): return "Integer vectors of length %s that sum to %s with constraints: \ %s"%(self.k, self.n, ", ".join( ["%s=%s"%(key, self._constraints[key]) for key in sorted(self._constraints.keys())] )) - def __contains__(self, x): """ TESTS:: diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index 8f3d9f2f56b..5c41f990dbb 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -305,9 +305,13 @@ def ambient(self): sage: S.ambient() Integer vectors """ - # TODO: Fix me once 'IntegerVectors(length=bla)' will return - # the integer vectors of length bla - return IntegerVectors(length=self.n) + ## TODO: Fix me once 'IntegerVectors(length=bla)' will return + ## the integer vectors of length bla + #return IntegerVectors(length=self.n) + + # (#17927) The previous line was replaced by the following, as + # IntegerVectors(length=k) is invalid at the moment. + return IntegerVectors() def lift(self, elt): r""" @@ -338,15 +342,15 @@ def retract(self, elt): EXAMPLES:: - sage: [0,0,0,0] in IntegerVectors(length=4) + sage: [0,0,0,0] in IntegerVectors(0,4) True - sage: [1,0,0,0] in IntegerVectors(length=4) + sage: [1,0,0,0] in IntegerVectors(1,4) True - sage: [0,1,0,0] in IntegerVectors(length=4) + sage: [0,1,0,0] in IntegerVectors(1,4) True - sage: [1,0,1,0] in IntegerVectors(length=4) + sage: [1,0,1,0] in IntegerVectors(2,4) True - sage: [0,1,0,1] in IntegerVectors(length=4) + sage: [0,1,0,1] in IntegerVectors(2,4) True sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]])) sage: S.retract([0,0,0,0]) @@ -814,9 +818,13 @@ def ambient(self): else: return IntegerVectors(n=self._sum, max_part=self._max_part) else: - # Fix me once max_part should be accepted as a single - # argument for integer vectors - return IntegerVectors(max_part=self._max_part) + ## Fix me once max_part should be accepted as a single + ## argument for integer vectors + #return IntegerVectors(max_part=self._max_part) + + # (#17927) The previous line was replaced by the following, as + # IntegerVectors(max_part=k) is invalid at the moment. + return IntegerVectors() def lift(self, elt): r""" @@ -827,7 +835,7 @@ def lift(self, elt): sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), max_part=1) sage: v = S.lift([1,0,1,0]); v [1, 0, 1, 0] - sage: v in IntegerVectors(max_part=1) + sage: v in IntegerVectors(2,4,max_part=1) True sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), sum=6) sage: v = S.lift(S.list()[5]); v diff --git a/src/sage/combinat/misc.py b/src/sage/combinat/misc.py index 3c5804a664b..44e6516af17 100644 --- a/src/sage/combinat/misc.py +++ b/src/sage/combinat/misc.py @@ -294,10 +294,6 @@ def __repr__(self): """ return "Iterable function call %s with args=%s and kwargs=%s"%(self.f, self.args, self.kwargs) - - - - def check_integer_list_constraints(l, **kwargs): """ EXAMPLES:: @@ -344,7 +340,6 @@ def check_integer_list_constraints(l, **kwargs): else: return [] - min_part = kwargs.get('min_part', None) max_part = kwargs.get('max_part', None) @@ -359,7 +354,7 @@ def check_integer_list_constraints(l, **kwargs): inner = kwargs.get('inner', None) outer = kwargs.get('outer', None) - #Preprocess the constraints + # Preprocess the constraints if outer is not None: max_length = len(outer) for i in range(max_length): From 7aa15491539d77764c8a4f2801396cdee5e98434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 09:57:04 -0400 Subject: [PATCH 269/665] 11111: moved quotient_module in Modules.WithBasis.FiniteDimensional + doc finalization --- .../finite_dimensional_modules_with_basis.py | 46 +++++++++++++++ src/sage/categories/modules_with_basis.py | 53 +++-------------- src/sage/modules/with_basis/subquotient.py | 59 +++++++++++++++++-- 3 files changed, 107 insertions(+), 51 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index c78e9d29c9d..9cd6edea429 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -217,6 +217,52 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): [action(s, b)._vector_() for b in self.basis()])) return map(self.from_vector, mat.left_kernel().basis()) + def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): + r""" + Construct the quotient free 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:`submodule`, which see. + + .. WARNING:: + + At this point, only quotients by free submodules whose + basis can be put in unitriangular echelon form are + supported. + + 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] + + .. 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, + already_echelonized=already_echelonized) + return QuotientModuleWithBasis(submodule, category=category) + class ElementMethods: pass diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index c69d98d1ab6..cd94cfc5ff2 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -621,6 +621,13 @@ def submodule(self, gens, The basis of the submodule uses the same index set as the generators, and the lifting map sends `y_i` to `gens[i]`. + + .. SEEALSO:: + + - :meth:`Modules.WithBasis.ParentMethods.submodule` + - :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` + - :class:`sage.modules.with_basis.subquotient.SubmoduleWithBasis` + EXAMPLES: We construct a submodule of the free `\QQ`-module generated by @@ -709,52 +716,6 @@ def submodule(self, gens, from sage.modules.with_basis.subquotient import SubmoduleWithBasis return SubmoduleWithBasis(gens, ambient=self, category=category) - def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): - r""" - Construct the quotient free 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:`submodule`, which see. - - - This # FIXME: The following currently works only if: - # - The ambient space is finite dimensional - # - The embedding is unitriangular - TODO: polish - - .. WARNING:: - - At this point, only quotients of finite dimensional - modules with basis by free submodules with unitriangular - echelon form are supported. - - 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] - """ - from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis - if not isinstance(submodule, SubmoduleWithBasis): - submodule = self.submodule(submodule, check=check, - already_echelonized=already_echelonized) - return QuotientModuleWithBasis(submodule, category=category) - def tensor(*parents): """ 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 62ed6587711..dd0fe21e615 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -23,10 +23,36 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): - ``category`` -- a category (default: ``ModulesWithBasis(submodule.base_ring())``) ``submodule`` is typically a :class:`SubmoduleWithBasis`. It - should implement a method ``reduce``, and it's ``lift`` method - should have a method ``.cokernel_basis_indices`` that compute the - indexing set of a subset of the basis of ``self`` that spans some - suplementary of ``submodule`` in the ambient space. + should implement a method ``reduce``. Futheremore its ``lift`` + method should have a method ``.cokernel_basis_indices`` that + computes the indexing set of a subset of the basis of ``self`` + that spans some suplementary of ``submodule`` in the ambient + space. Mathematically speaking, ``submodule`` should be a free + submodule whose basis can be put in unitriangular echelon form. + + This is meant to be constructed via + :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` + + This differs from :class:`sage.rings.quotient_ring.QuotientRing` + in the following ways: + + - The submodule needs not be an ideal. If it is, the + transportation of the ring structure is taken care of by the + ``Subquotients`` categories. + + - Thanks to ``.cokernel_basis_indices``, we know the indices of a + basis of the quotient, and elements are represented directly in + the free module spanned by those indices rather than by wrapping + elements of the ambient space. + + There is room for sharing more code between those two + implementations and generalizing them. See :trac:`18204`. + + .. SEEALSO:: + + - :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` + - :class:`SubmoduleWithBasis` + - :class:`sage.rings.quotient_ring.QuotientRing` """ @staticmethod def __classcall_private__(cls, submodule, category=None): @@ -130,12 +156,33 @@ class SubmoduleWithBasis(CombinatorialFreeModule): r""" A base class for submodules of a ModuleWithBasis spanned by a (possibly infinite) basis in echelon form. + + INPUT: + + - ``basis`` -- a family of vectors in echelon form in some + :class:`module with basis ` `V`, or data that + can be converted into such a family + + - ``ambient`` -- the ambient space `V` + + - ``category`` -- a category + + Further arguments are passed down to + :class:`CombinatorialFreeModule`. + + This is meant to be constructed via + :meth:`Modules.WithBasis.ParentMethods.submodule`. + + .. SEEALSO:: + + - :meth:`Modules.WithBasis.ParentMethods.submodule` + - :class:`QuotientModuleWithBasis` """ @staticmethod def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts): r""" - Normalize the input + Normalize the input. TESTS:: @@ -156,6 +203,8 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts def __init__(self, basis, ambient, category): r""" + Initialization. + TESTS:: sage: from sage.modules.with_basis.subquotient import SubmoduleWithBasis From 2c3dac1c66bf85adc784db49796620e3b3894042 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 15 Apr 2015 11:14:35 -0400 Subject: [PATCH 270/665] Fixing pickling. --- src/sage/combinat/ribbon_shaped_tableau.py | 38 ++++++------- src/sage/combinat/ribbon_tableau.py | 38 ++++++------- src/sage/combinat/skew_tableau.py | 56 +++++++++---------- src/sage/combinat/tableau.py | 64 +++++++++++----------- 4 files changed, 99 insertions(+), 97 deletions(-) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 04a1050e13c..d201067a925 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -112,24 +112,6 @@ def __init__(self, parent, t): SkewTableau.__init__(self, parent, t) - def __setstate__(self, state): - r""" - In order to maintain backwards compatibility and be able to unpickle - a old pickle from ``Ribbon_class`` we have to override the - default ``__setstate__``. - - EXAMPLES:: - - sage: loads(dumps( RibbonShapedTableau([[3,2,1], [1,1]]) )) # indirect doctest - [[None, 3, 2, 1], [1, 1]] - """ - if isinstance(state, dict): # for old pickles from Ribbon_class - self._set_parent(StandardRibbonShapedTableaux()) - self.__dict__ = state - else: - self._set_parent(state[0]) - self.__dict__ = state[1] - def height(self): """ Return the height of ``self``. @@ -394,7 +376,25 @@ def __iter__(self): for p in descents_composition_list(self.shape): yield self.from_permutation(p) +class Ribbon_class(RibbonShapedTableau): + """ + This exists solely for unpickling ``Ribbon_class`` objects. + """ + def __setstate__(self, state): + r""" + Unpickle old ``Ribbon_class`` objects. + + EXAMPLES:: + + sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@\x14]\x8a\x0e\xdf\xb8\x968"\xceZ|\x00x\xef5\x11') + [[None, 1], [2, 3]] + sage: loads(dumps( RibbonTableau([[None, 1],[2,3]]) )) + [[None, 1], [2, 3]] + """ + self.__class__ = RibbonTableau + self.__init__(RibbonTableaux(), state['_list']) + from sage.structure.sage_object import register_unpickle_override -register_unpickle_override('sage.combinat.ribbon_tableau', 'RibbonTableau_class', RibbonTableau) +register_unpickle_override('sage.combinat.ribbon_tableau', 'RibbonTableau_class', RibbonTableau_class) register_unpickle_override('sage.combinat.ribbon_tableau', 'RibbonTableaux_shapeweightlength', RibbonTableaux) register_unpickle_override('sage.combinat.ribbon_tableau', 'SemistandardMultiSkewTtableaux_shapeweight', SemistandardMultiSkewTableaux) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 7db54795d13..19ad9c98f3c 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -121,17 +121,17 @@ def __eq__(self, other): r""" Check whether ``self`` is equal to ``other``. - TODO: + .. TODO:: - This overwrites the equality check of - :class:`~sage.structure.list_clone.ClonableList` - in order to circumvent the coercion framework. - Eventually this should be solved more elegantly, - for example along the lines of what was done for - k-tableaux. + This overwrites the equality check of + :class:`~sage.structure.list_clone.ClonableList` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + `k`-tableaux. - For now, two elements are equal if their underlying - defining lists compare equal. + For now, two elements are equal if their underlying + defining lists compare equal. INPUT: @@ -204,24 +204,6 @@ def check(self): if not row: raise TypeError("a skew tableau cannot have an empty list for a row") - def __setstate__(self, state): - r""" - In order to maintain backwards compatibility and be able to unpickle - a old pickle from ``SkewTableau_class`` we have to override the - default ``__setstate__``. - - EXAMPLES:: - - sage: loads(dumps( SkewTableau([[1,1], [3,2,1]]) )) # indirect doctest - [[1, 1], [3, 2, 1]] - """ - if isinstance(state, dict): # for old pickles from SkewTableau_class - self._set_parent(SkewTableaux()) - self.__dict__ = state - else: - self._set_parent(state[0]) - self.__dict__ = state[1] - def _repr_(self): """ Return a string representation of ``self``. @@ -2319,6 +2301,24 @@ def __iter__(self): for x in RibbonTableaux_shape_weight_length(self.p, self.mu, 1): yield self.element_class(self, x) +class SkewTableau_class(SkewTableau): + """ + This exists solely for unpickling ``SkewTableau_class`` objects. + """ + def __setstate__(self, state): + r""" + Unpickle old ``SkewTableau_class`` objects. + + TESTS:: + + sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+H,*\xc9,\xc9\xcc\xcf\xe3\n\x80\xb1\xe2\x93s\x12\x8b\x8b\xb9\n\x195\x1b\x0b\x99j\x0b\x995BY\xe33\x12\x8b3\nY\xfc\x80\xac\x9c\xcc\xe2\x92B\xd6\xd8B6\r\x88IE\x99y\xe9\xc5z\x99y%\xa9\xe9\xa9E\\\xb9\x89\xd9\xa9\xf10N!{(\xa3qkP!G\x06\x90a\x04dp\x82\x18\x86@\x06Wji\x92\x1e\x00x0.\xb5') + [3, 2, 1] + sage: loads(dumps( SkewTableau([[1,1], [3,2,1]]) )) # indirect doctest + [[1, 1], [3, 2, 1]] + """ + self.__class__ = SkewTableau + self.__init__(SkewTableaux(), state['_list']) + # October 2012: fixing outdated pickles which use the classes being deprecated from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.combinat.skew_tableau', 'StandardSkewTableaux_n', StandardSkewTableaux_size) @@ -2328,5 +2328,5 @@ def __iter__(self): register_unpickle_override('sage.combinat.skew_tableau', 'SemistandardSkewTableaux_pmu', SemistandardSkewTableaux_shape_weight) # July 2013: But wait, there more! register_unpickle_override('sage.combinat.skew_tableau', 'StandardSkewTableaux_skewpartition', StandardSkewTableaux_shape) -register_unpickle_override('sage.combinat.skew_tableau', 'SkewTableau_class', SkewTableau) +register_unpickle_override('sage.combinat.skew_tableau', 'SkewTableau_class', SkewTableau_class) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 60e80672d0b..0cc8b8fe065 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -332,17 +332,17 @@ def __eq__(self, other): r""" Check whether ``self`` is equal to ``other``. - TODO: + .. TODO:: - This overwrites the equality check of - :class:`~sage.structure.list_clone.ClonableList` - in order to circumvent the coercion framework. - Eventually this should be solved more elegantly, - for example along the lines of what was done for - k-tableaux. + This overwrites the equality check of + :class:`~sage.structure.list_clone.ClonableList` + in order to circumvent the coercion framework. + Eventually this should be solved more elegantly, + for example along the lines of what was done for + `k`-tableaux. - For now, two elements are equal if their underlying - defining lists compare equal. + For now, two elements are equal if their underlying + defining lists compare equal. INPUT: @@ -413,24 +413,6 @@ def check(self): if lens and lens[-1] == 0: raise ValueError("A tableau must not have empty rows.") - def __setstate__(self, state): - """ - In order to maintain backward compatibility and be able to unpickle an - old pickle from the now deprecated :class:`Tableau_class` we have to - override the default :meth:`__setstate__`. - - TESTS:: - - sage: loads(dumps( Tableau([[1]]) )) # indirect doctest for unpickling a Tableau element - [[1]] - """ - if isinstance(state, dict): # for old pickles from Tableau_class - self._set_parent(Tableaux()) - self.__dict__ = state - else: - self._set_parent(state[0]) - self.__dict__ = state[1] - def _repr_(self): """ Return a string representation of ``self``. @@ -500,9 +482,9 @@ def _repr_compact(self): sage: Tableau([])._repr_compact() '-' """ - if len(self)==0: + if not self: return '-' - else: return '/'.join(','.join('%s'%r for r in row) for row in self) + return '/'.join(','.join('%s'%r for r in row) for row in self) def _ascii_art_(self): """ @@ -1714,7 +1696,7 @@ def leq(self, secondtab): True """ if not secondtab in Tableaux(): - raise TypeError(str(secondtab) + " must be a tableau") + raise TypeError("{} must be a tableau".format(secondtab)) sh = self.shape() if sh != secondtab.shape(): raise TypeError("the tableaux must be the same shape") @@ -6365,9 +6347,29 @@ def symmetric_group_action_on_values(word, perm): w[i] = l return w + + +class Tableau_class(Tableau): + """ + This exists solely for unpickling ``Tableau_class`` objects. + """ + def __setstate__(self, state): + r""" + Unpickle old ``Tableau_class`` objects. + + TESTS:: + + sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+IL\xcaIM,\xe5\n\x81\xd0\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl![l!;\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x9031\xb14I\x0f\x00\xf6\xae)7') + [[1]] + sage: loads(dumps( Tableau([[1]]) )) + [[1]] + """ + self.__class__ = Tableau + self.__init__(Tableaux(), state['_list']) + # October 2012: fixing outdated pickles which use classed being deprecated from sage.structure.sage_object import register_unpickle_override -register_unpickle_override('sage.combinat.tableau', 'Tableau_class', Tableau) +register_unpickle_override('sage.combinat.tableau', 'Tableau_class', Tableau_class) register_unpickle_override('sage.combinat.tableau', 'Tableaux_n', Tableaux_size) register_unpickle_override('sage.combinat.tableau', 'StandardTableaux_n', StandardTableaux_size) register_unpickle_override('sage.combinat.tableau', 'StandardTableaux_partition', StandardTableaux_shape) From e9a7b562c832dbb78a3554a22aadee5a39c05b3a Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 17:43:30 +0200 Subject: [PATCH 271/665] RibbonShapedTableau instances were cuckolding from StandardRibbonShapedTableaux and thus from StandardSkewTableaux --- src/sage/combinat/all.py | 2 +- src/sage/combinat/ribbon_shaped_tableau.py | 78 +++++++++++++++++++++- src/sage/combinat/ribbon_tableau.py | 8 ++- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 26310e8566b..f16f684a03f 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -86,7 +86,7 @@ from tableau import Tableau, SemistandardTableau, StandardTableau, \ Tableaux, StandardTableaux, SemistandardTableaux from skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux, SemistandardSkewTableaux -from ribbon_shaped_tableau import RibbonShapedTableau, StandardRibbonShapedTableaux +from ribbon_shaped_tableau import RibbonShapedTableau, RibbonShapedTableaux, StandardRibbonShapedTableaux from ribbon_tableau import RibbonTableaux, RibbonTableau, MultiSkewTableaux, MultiSkewTableau, SemistandardMultiSkewTableaux from composition_tableau import CompositionTableau, CompositionTableaux diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index d201067a925..3e62638736a 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -16,12 +16,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.combinat.skew_tableau import SkewTableau, StandardSkewTableaux +from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux from sage.combinat.tableau import TableauOptions from sage.combinat.permutation import Permutation, descents_composition_first, descents_composition_list, descents_composition_last 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.sets_cat import Sets class RibbonShapedTableau(SkewTableau): r""" @@ -153,6 +154,74 @@ def width(self): return len(self[0]) if len(self) > 0 else 0 +class RibbonShapedTableaux(SkewTableaux): + """ + The set of all ribbon shaped tableaux. + """ + @staticmethod + def __classcall_private__(cls, shape=None, **kwds): + """ + Normalize input to ensure a unique representation and pick the correct + class based on input. + + The ``shape`` parameter is currently ignored. + + EXAMPLES:: + + sage: S1 = RibbonShapedTableaux([4, 2, 2, 1]) + sage: S2 = RibbonShapedTableaux((4, 2, 2, 1)) + sage: S1 is S2 + True + """ + #if shape is not None: + # from sage.combinat.partition import Partition + # return RibbonShapedTableaux_shape(Partition(shape)) + + # Otherwise arg0 takes the place of the category in pickling + return super(RibbonShapedTableaux, cls).__classcall__(cls, **kwds) + + def __init__(self, category=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: S = RibbonShapedTableaux() + sage: TestSuite(S).run() + """ + if category is None: + category = Sets() + + SkewTableaux.__init__(self, category=category) + + def _repr_(self): + """ + TESTS:: + + sage: repr(RibbonShapedTableaux()) # indirect doctest + 'Ribbon shaped tableaux' + """ + return "Ribbon shaped tableaux" + + Element = RibbonShapedTableau + global_options = TableauOptions + + def from_shape_and_word(self, shape, word): + """ + Return the ribbon corresponding to the given ribbon shape and word. + + EXAMPLES:: + + sage: RibbonShapedTableaux().from_shape_and_word([1,3],[1,3,3,7]) + [[None, None, 1], [3, 3, 7]] + """ + pos = 0 + r = [] + for l in shape: + r.append(word[pos:pos+l]) + pos += l + return self.element_class(self, r) + class StandardRibbonShapedTableaux(StandardSkewTableaux): """ The set of all standard ribbon shaped tableaux. @@ -221,8 +290,7 @@ def __iter__(self): [[None, 1], [2, 3]], [[1], [2], [3]], [[1, 2, 3, 4]], - [[None, None, 3], - [1, 2, 4]]] + [[None, None, 3], [1, 2, 4]]] """ from sage.combinat.partition import _Partitions for p in _Partitions: @@ -384,6 +452,10 @@ def __setstate__(self, state): r""" Unpickle old ``Ribbon_class`` objects. + Due to a bug in the implementation, the result will have parent + :class:`StandardRibbonShapedTableaux`, even if it is not + standard. Rebuild the tableau to get it into the right parent. + EXAMPLES:: sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@ Date: Tue, 14 Apr 2015 10:14:40 +0200 Subject: [PATCH 272/665] #5332 Prefer R. = ... to R, x = ....objgen() in examples ...involving polynomial rings --- src/sage/categories/homset.py | 5 ++--- src/sage/rings/ideal.py | 9 ++++----- src/sage/rings/morphism.pyx | 4 ++-- src/sage/rings/polynomial/multi_polynomial_ideal.py | 6 +++--- src/sage/rings/polynomial/multi_polynomial_ring.py | 8 +++++++- src/sage/rings/polynomial/polynomial_element.pyx | 7 +++++-- src/sage/schemes/elliptic_curves/ell_generic.py | 4 ++-- 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 0a11a248730..da15286b040 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -426,8 +426,7 @@ def hom(X, Y, f): EXAMPLES:: - sage: R, x = PolynomialRing(QQ,'x').objgen() - sage: phi = hom(R, QQ, [2]) + sage: phi = hom(QQ['x'], QQ, [2]) sage: phi(x^2 + 3) 7 """ @@ -503,7 +502,7 @@ def end(X, f): EXAMPLES:: - sage: R, x = PolynomialRing(QQ,'x').objgen() + sage: R. = QQ[] sage: phi = end(R, [x + 1]) sage: phi Ring endomorphism of Univariate Polynomial Ring in x over Rational Field diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index ea505a7ac85..cde642dc404 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -63,7 +63,7 @@ def Ideal(*args, **kwds): EXAMPLES:: - sage: R, x = PolynomialRing(ZZ, 'x').objgen() + sage: R. = ZZ[] sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: I Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring @@ -136,7 +136,7 @@ def Ideal(*args, **kwds): TESTS:: - sage: R, x = PolynomialRing(ZZ, 'x').objgen() + sage: R. = ZZ[] sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: I == loads(dumps(I)) True @@ -249,9 +249,8 @@ def __init__(self, ring, gens, coerce=True): EXAMPLES:: - sage: R, x = PolynomialRing(ZZ, 'x').objgen() - sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) - sage: I + sage: R. = ZZ[] + sage: R.ideal([4 + 3*x + x^2, 1 + x^2]) Ideal (x^2 + 3*x + 4, x^2 + 1) of Univariate Polynomial Ring in x over Integer Ring """ self.__ring = ring diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index cca2c43c5a8..6c8ec24271c 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -40,7 +40,7 @@ Reduction to finite field:: Map from single variable polynomial ring:: - sage: R, x = PolynomialRing(ZZ, 'x').objgen() + sage: R. = ZZ[] sage: phi = R.hom([2], GF(5)) sage: phi Ring morphism: @@ -417,7 +417,7 @@ cdef class RingMap_lift(RingMap): EXAMPLES:: - sage: R, (x,y) = PolynomialRing(QQ, 2, 'xy').objgens() + sage: R. = QQ[] sage: S. = R.quo( (x^2 + y^2, y) ) sage: S.lift() Set-theoretic ring morphism: diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index d940e3cd861..309eabaff57 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1454,7 +1454,7 @@ def genus(self): Consider the hyperelliptic curve `y^2 = 4x^5 - 30x^3 + 45x - 22` over `\QQ`, it has genus 2:: - sage: P, x = PolynomialRing(QQ,"x").objgen() + sage: P. = QQ[] sage: f = 4*x^5 - 30*x^3 + 45*x - 22 sage: C = HyperellipticCurve(f); C Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22 @@ -3234,7 +3234,7 @@ def __eq__(self, other): :: - sage: R, (x,y) = PolynomialRing(QQ, 2, 'xy').objgens() + sage: R. = QQ[] sage: I = (x^3 + y, y)*R sage: J = (x^3 + y, y, y*x^3 + y^2)*R sage: I == J @@ -3857,7 +3857,7 @@ def _contains_(self, f): EXAMPLES:: - sage: R, (x,y) = PolynomialRing(QQ, 2, 'xy').objgens() + sage: R. = QQ[] sage: I = (x^3 + y, y)*R sage: x in I # indirect doctest False diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index 1760d528467..cd084c58865 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -27,7 +27,7 @@ We construct the Frobenius morphism on `\GF{5}[x,y,z]` over `\GF{5}`:: - sage: R, (x,y,z) = PolynomialRing(GF(5), 3, 'xyz').objgens() + sage: R. = GF(5)[] sage: frob = R.hom([x^5, y^5, z^5]) sage: frob(x^2 + 2*y - z^4) -z^20 + x^10 + 2*y^5 @@ -43,6 +43,12 @@ sage: S. = PowerSeriesRing(R) sage: t*(x+y) (x + y)*t + +TESTS:: + + sage: PolynomialRing(GF(5), 3, 'xyz').objgens() + (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5, + (x, y, z)) """ #***************************************************************************** diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 9b0c7b368a5..0ec63e4dc00 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -25,6 +25,9 @@ TESTS:: sage: f = x^5 + 2*x^2 + (-1) sage: f == loads(dumps(f)) True + + sage: PolynomialRing(ZZ,'x').objgen() + (Univariate Polynomial Ring in x over Integer Ring, x) """ #***************************************************************************** @@ -6150,7 +6153,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: P,x=PolynomialRing(ZZ,'x').objgen() + sage: P. = ZZ[] sage: (x^2+x).valuation() 1 sage: (x^2+x).valuation(x+1) @@ -6203,7 +6206,7 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: P,x=PolynomialRing(ZZ,'x').objgen() + sage: R. = ZZ[] sage: (x^2+x).ord(x+1) 1 """ diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index cf876c7d305..2d8d047af99 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -13,8 +13,8 @@ We construct an elliptic curve over an elaborate base ring:: sage: p = 97; a=1; b=3 - sage: R, u = PolynomialRing(GF(p), 'u').objgen() - sage: S, v = PolynomialRing(R, 'v').objgen() + sage: R. = GF(p)[] + sage: S. = R[] sage: T = S.fraction_field() sage: E = EllipticCurve(T, [a, b]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Fraction Field of Univariate Polynomial Ring in v over Univariate Polynomial Ring in u over Finite Field of size 97 From be20eb88e7e55711cd67cea4a7848043eb11e92d Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 15 Apr 2015 19:46:42 +0200 Subject: [PATCH 273/665] Trac 5332: remove more objgen(s) from the doc --- .../notes/2006-01-16-pari_ntl_benchmark.txt | 4 +- src/sage/modular/dirichlet.py | 4 +- src/sage/modular/modsym/ambient.py | 12 +-- src/sage/monoids/free_monoid_element.py | 2 +- .../finite_rings/finite_field_ext_pari.py | 4 +- .../rings/finite_rings/finite_field_givaro.py | 4 +- .../finite_rings/finite_field_pari_ffelt.py | 4 +- src/sage/rings/fraction_field_element.pyx | 3 +- src/sage/rings/laurent_series_ring.py | 3 +- .../number_field/number_field_element.pyx | 2 +- .../polynomial/multi_polynomial_element.py | 4 +- .../polynomial/multi_polynomial_ideal.py | 3 +- .../rings/polynomial/polynomial_element.pyx | 8 +- src/sage/rings/power_series_poly.pyx | 2 +- src/sage/rings/power_series_ring_element.pyx | 3 +- src/sage/schemes/elliptic_curves/padics.py | 76 +++++++++---------- src/sage/schemes/generic/algebraic_scheme.py | 2 +- .../hyperelliptic_curves/monsky_washnitzer.py | 6 +- src/sage/schemes/plane_curves/affine_curve.py | 2 +- .../schemes/plane_quartics/quartic_generic.py | 5 +- .../schemes/projective/projective_space.py | 14 +++- src/sage/structure/category_object.pyx | 2 +- 22 files changed, 93 insertions(+), 76 deletions(-) diff --git a/src/sage/libs/ntl/notes/2006-01-16-pari_ntl_benchmark.txt b/src/sage/libs/ntl/notes/2006-01-16-pari_ntl_benchmark.txt index ff022a67847..963e009d100 100644 --- a/src/sage/libs/ntl/notes/2006-01-16-pari_ntl_benchmark.txt +++ b/src/sage/libs/ntl/notes/2006-01-16-pari_ntl_benchmark.txt @@ -10,7 +10,7 @@ make matrices over finite fields in PARI and computer their kernel. First a small example so what is going on is clearer: -sage: k,a = GF(2^8).objgen() +sage: k. = GF(2^8) sage: A = MatrixSpace(k,3,5)([k.random_element() for _ in range(3*5)]) sage: A [ a^5 + a^3 + a^2 a^7 + a^6 + a^2 + 1 a^7 + a^6 + a^4 + a^2 a^3 + a^2 + a a^6 + 1] @@ -40,7 +40,7 @@ Basis matrix: OK, now here's an example to get a sense of speed: -sage: k,a = GF(2^8).objgen() +sage: k. = GF(2^8) sage: A = MatrixSpace(k,50,50)([k.random_element() for _ in range(50*50)]) sage: B = pari(A) sage: time v= B.matker() diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 9f254a1989f..5416867eda5 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -202,7 +202,7 @@ def __init__(self, parent, x, check=True): EXAMPLES:: - sage: G, e = DirichletGroup(13).objgen() + sage: G. = DirichletGroup(13) sage: G Group of Dirichlet characters of modulus 13 over Cyclotomic Field of order 12 and degree 4 sage: e @@ -212,7 +212,7 @@ def __init__(self, parent, x, check=True): :: - sage: G, x = DirichletGroup(35).objgens() + sage: G. = DirichletGroup(35) sage: e = x[0]*x[1]; e Dirichlet character modulo 35 of conductor 35 mapping 22 |--> zeta12^3, 31 |--> zeta12^2 sage: e.order() diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 6e43948fee7..43a1cfb0e40 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -3480,7 +3480,7 @@ def __init__(self, eps, weight, sign, base_ring, custom_init=None): Here is another example:: - sage: G, e = DirichletGroup(5).objgen() + sage: G. = DirichletGroup(5) sage: M = ModularSymbols(e,3) sage: loads(M.dumps()) == M True @@ -3500,7 +3500,7 @@ def _repr_(self): EXAMPLES:: - sage: G, e = DirichletGroup(5).objgen() + sage: G. = DirichletGroup(5) sage: M = ModularSymbols(e,3) sage: M # indirect doctest Modular Symbols space of dimension 2 and level 5, weight 3, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2 @@ -3516,7 +3516,7 @@ def _cuspidal_submodule_dimension_formula(self): EXAMPLES:: - sage: G, e = DirichletGroup(50).objgen() + sage: G. = DirichletGroup(50) sage: M = ModularSymbols(e^2,2) sage: M.dimension() 16 @@ -3537,7 +3537,7 @@ def _cuspidal_new_submodule_dimension_formula(self): EXAMPLES:: - sage: G, e = DirichletGroup(50).objgen() + sage: G. = DirichletGroup(50) sage: M = ModularSymbols(e,3) sage: M.dimension() 30 @@ -3577,7 +3577,7 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R, character_twist=Fa EXAMPLES:: - sage: G, e = DirichletGroup(5).objgen() + sage: G. = DirichletGroup(5) sage: M = ModularSymbols(e,3) sage: M.dimension() 2 @@ -3825,7 +3825,7 @@ def _hecke_images(self, i, v): EXAMPLES:: - sage: G, e = DirichletGroup(50,QQ).objgen() + sage: G. = DirichletGroup(50,QQ) sage: M = ModularSymbols(e^2,2) sage: M.dimension() 15 diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index acd631e2ceb..6b067706287 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -137,7 +137,7 @@ def _latex_(self): sage: z = F([(0,5),(1,2),(0,10),(0,2),(1,2)]) sage: z._latex_() 'a_{0}^{5}a_{1}^{2}a_{0}^{12}a_{1}^{2}' - sage: F, (alpha,beta,gamma) = FreeMonoid(3, 'alpha,beta,gamma').objgens() + sage: F. = FreeMonoid(3) sage: latex(alpha*beta*gamma) \alpha\beta\gamma """ diff --git a/src/sage/rings/finite_rings/finite_field_ext_pari.py b/src/sage/rings/finite_rings/finite_field_ext_pari.py index 0af8183cc55..df4ebdfbb3a 100644 --- a/src/sage/rings/finite_rings/finite_field_ext_pari.py +++ b/src/sage/rings/finite_rings/finite_field_ext_pari.py @@ -389,7 +389,7 @@ def _element_constructor_(self, x): the polynomial at the field's generator:: sage: R. = QQ[] - sage: k, a = FiniteField(5^2, 'a', impl='pari_mod').objgen() + sage: k. = FiniteField(5^2, impl='pari_mod') sage: k(R(2/3)) 4 sage: k(x^2) @@ -402,7 +402,7 @@ def _element_constructor_(self, x): sage: k(x^25) a - sage: Q, q = FiniteField(5^7, 'q', impl='pari_mod').objgen() + sage: Q. = FiniteField(5^7, impl='pari_mod') sage: L = GF(5) sage: LL. = L[] sage: Q(xx^2 + 2*xx + 4) diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index 68e4b7620ce..d96fbf75299 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -305,7 +305,7 @@ def _element_constructor_(self, e): the polynomial at the field's generator:: sage: R. = QQ[] - sage: k, a = FiniteField(5^2, 'a', impl='givaro').objgen() + sage: k. = FiniteField(5^2, 'a', impl='givaro') sage: k(R(2/3)) 4 sage: k(x^2) @@ -318,7 +318,7 @@ def _element_constructor_(self, e): sage: k(x^25) a - sage: Q, q = FiniteField(5^3, 'q', impl='givaro').objgen() + sage: Q. = FiniteField(5^3, 'q', impl='givaro') sage: L = GF(5) sage: LL. = L[] sage: Q(xx^2 + 2*xx + 4) diff --git a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py index 286ce0d4caf..dbc5d8e45af 100644 --- a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py +++ b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py @@ -237,7 +237,7 @@ def _element_constructor_(self, x): the polynomial at the field's generator:: sage: R. = QQ[] - sage: k, a = FiniteField(5^2, 'a', impl='pari_ffelt').objgen() + sage: k. = FiniteField(5^2, 'a', impl='pari_ffelt') sage: k(R(2/3)) 4 sage: k(x^2) @@ -251,7 +251,7 @@ def _element_constructor_(self, x): sage: k(x^25) a - sage: Q, q = FiniteField(5^7, 'q', impl='pari_ffelt').objgen() + sage: Q. = FiniteField(5^7, 'q', impl='pari_ffelt') sage: L = GF(5) sage: LL. = L[] sage: Q(xx^2 + 2*xx + 4) diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index b55bf42dc07..2b320d3c2e1 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -67,11 +67,12 @@ cdef class FractionFieldElement(FieldElement): """ EXAMPLES:: - sage: K, x = FractionField(PolynomialRing(QQ, 'x')).objgen() + sage: K = FractionField(PolynomialRing(QQ, 'x')) sage: K Fraction Field of Univariate Polynomial Ring in x over Rational Field sage: loads(K.dumps()) == K True + sage: x = K.gen() sage: f = (x^3 + x)/(17 - x^19); f (x^3 + x)/(-x^19 + 17) sage: loads(f.dumps()) == f diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 8d5b757f631..dff57ad04b6 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -139,7 +139,8 @@ class LaurentSeriesRing_generic(commutative_ring.CommutativeRing): EXAMPLES:: - sage: K, q = LaurentSeriesRing(CC, 'q').objgen(); K + sage: K = LaurentSeriesRing(CC, 'q') + sage: K Laurent Series Ring in q over Complex Field with 53 bits of precision sage: loads(K.dumps()) == K True diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index c051e7d438a..e54bb0cd8f7 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -525,7 +525,7 @@ cdef class NumberFieldElement(FieldElement): EXAMPLES:: - sage: C,zeta12=CyclotomicField(12).objgen() + sage: C. = CyclotomicField(12) sage: latex(zeta12^4-zeta12) # indirect doctest \zeta_{12}^{2} - \zeta_{12} - 1 """ diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 11239961c9f..5c88ba26b88 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -344,8 +344,8 @@ def __init__(self, parent, x): """ EXAMPLES:: - sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() - sage: x + sage: R = PolynomialRing(QQbar, 10, 'x') + sage: R.gens() (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) sage: loads(dumps(x)) == x True diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 309eabaff57..54e7e2d94c0 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4057,7 +4057,8 @@ def degree_of_semi_regularity(self): from sage.misc.misc_c import prod from sage.rings.power_series_ring import PowerSeriesRing - R,z = PowerSeriesRing(QQ,'z', default_prec=sum(degs)).objgen() + R = PowerSeriesRing(QQ,'z', default_prec=sum(degs)) + z = R.gen() dreg = 0 s = prod([1-z**d for d in degs]) / (1-z)**n for dreg in xrange(0,sum(degs)): diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 0ec63e4dc00..a151ccb20f5 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -181,8 +181,12 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLE:: - sage: R. = QQ['y'] - sage: S. = R['x'] + sage: R = QQ['x']['y'] + sage: R + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x + over Rational Field + sage: y = R.gen() + sage: x = R.base_ring().gen() sage: f = x*y; f y*x sage: type(f) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 24c4b8fb5bf..93d457b935e 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -23,7 +23,7 @@ cdef class PowerSeries_poly(PowerSeries): """ EXAMPLES:: - sage: R, q = PowerSeriesRing(CC, 'q').objgen() + sage: R. = PowerSeriesRing(CC) sage: R Power Series Ring in q over Complex Field with 53 bits of precision sage: loads(q.dumps()) == q diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 931aa31b414..7cb512c5e81 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -34,7 +34,8 @@ EXAMPLE:: In Python (as opposed to Sage) create the power series ring and its generator as follows:: - sage: R, x = objgen(PowerSeriesRing(ZZ, 'x')) + sage: R = PowerSeriesRing(ZZ, 'x') + sage: x = R.gen() sage: parent(x) Power Series Ring in x over Integer Ring diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index f50969253b4..d552da37d76 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -227,7 +227,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_regulator(5, max_prec) # long time sage: for prec in range(1, max_prec): # long time - ... assert E.padic_regulator(5, prec) == full # long time + ....: assert E.padic_regulator(5, prec) == full # long time A case where the generator belongs to the formal group already (trac #3632):: @@ -444,15 +444,15 @@ def _multiply_point(E, R, P, m): sage: from sage.schemes.elliptic_curves.padics import _multiply_point sage: Q = P sage: for n in range(1, 25): - ... naive = R(Q[0].numerator()), \ - ... R(Q[1].numerator()), \ - ... R(Q[0].denominator().sqrt()) - ... triple = _multiply_point(E, R, P, n) - ... assert (triple[0] == naive[0]) and ( \ - ... (triple[1] == naive[1] and triple[2] == naive[2]) or \ - ... (triple[1] == -naive[1] and triple[2] == -naive[2])), \ - ... "_multiply_point() gave an incorrect answer" - ... Q = Q + P + ....: naive = R(Q[0].numerator()), \ + ....: R(Q[1].numerator()), \ + ....: R(Q[0].denominator().sqrt()) + ....: triple = _multiply_point(E, R, P, n) + ....: assert (triple[0] == naive[0]) and ( \ + ....: (triple[1] == naive[1] and triple[2] == naive[2]) or \ + ....: (triple[1] == -naive[1] and triple[2] == -naive[2])), \ + ....: "_multiply_point() gave an incorrect answer" + ....: Q = Q + P """ assert m >= 1 @@ -605,7 +605,7 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_height(5, max_prec)(P) # long time sage: for prec in range(1, max_prec): # long time - ... assert E.padic_height(5, prec)(P) == full # long time + ....: assert E.padic_height(5, prec)(P) == full # long time A supersingular prime for a curve:: @@ -797,7 +797,7 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): sage: max_prec = 30 # make sure we get past p^2 # long time sage: full = E.padic_height(5, max_prec)(P) # long time sage: for prec in range(2, max_prec): # long time - ... assert E.padic_height_via_multiply(5, prec)(P) == full # long time + ....: assert E.padic_height_via_multiply(5, prec)(P) == full # long time """ if check_hypotheses: if not p.is_prime(): @@ -981,8 +981,8 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): sage: E2 = E.padic_E2(5, max_N) # long time sage: max_sigma = E.padic_sigma(p, max_N, E2=E2) # long time sage: for N in range(3, max_N): # long time - ... sigma = E.padic_sigma(p, N, E2=E2) # long time - ... assert sigma == max_sigma + ....: sigma = E.padic_sigma(p, N, E2=E2) # long time + ....: assert sigma == max_sigma """ if check_hypotheses: p = __check_padic_hypotheses(self, p) @@ -1168,10 +1168,10 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) sage: E = EllipticCurve([1, 2, 3, 4, 7]) # long time sage: E2 = E.padic_E2(5, 50) # long time sage: for N in range(2, 10): # long time - ... for lamb in range(10): # long time - ... correct = E.padic_sigma(5, N + 3*lamb, E2=E2) # long time - ... compare = E.padic_sigma_truncated(5, N=N, lamb=lamb, E2=E2) # long time - ... assert compare == correct # long time + ....: for lamb in range(10): # long time + ....: correct = E.padic_sigma(5, N + 3*lamb, E2=E2) # long time + ....: compare = E.padic_sigma_truncated(5, N=N, lamb=lamb, E2=E2) # long time + ....: assert compare == correct # long time """ if check_hypotheses: p = __check_padic_hypotheses(self, p) @@ -1626,26 +1626,26 @@ def _brent(F, p, N): sage: brent = sage.schemes.elliptic_curves.padics._brent sage: for p in [2, 3, 5]: - ... for N in [2, 3, 10, 50]: - ... R = Integers(p**(N-1)) - ... Rx, x = PowerSeriesRing(R, "x").objgen() - ... for _ in range(5): - ... g = [R.random_element() for i in range(N)] - ... g[0] = R(1) - ... g = Rx(g, len(g)) - ... f = g.derivative() / g - ... # perturb f by something whose integral is in I - ... err = [R.random_element() * p**(N-i) for i in range(N+1)] - ... err = Rx(err, len(err)) - ... err = err.derivative() - ... F = f + err - ... # run brent() and compare output modulo I - ... G = brent(F, p, N) - ... assert G.prec() >= N, "not enough output terms" - ... err = (G - g).list() - ... for i in range(len(err)): - ... assert err[i].lift().valuation(p) >= (N - i), \ - ... "incorrect precision output" + ....: for N in [2, 3, 10, 50]: + ....: R = Integers(p**(N-1)) + ....: Rx. = PowerSeriesRing(R, "x") + ....: for _ in range(5): + ....: g = [R.random_element() for i in range(N)] + ....: g[0] = R(1) + ....: g = Rx(g, len(g)) + ....: f = g.derivative() / g + ....: # perturb f by something whose integral is in I + ....: err = [R.random_element() * p**(N-i) for i in range(N+1)] + ....: err = Rx(err, len(err)) + ....: err = err.derivative() + ....: F = f + err + ....: # run brent() and compare output modulo I + ....: G = brent(F, p, N) + ....: assert G.prec() >= N, "not enough output terms" + ....: err = (G - g).list() + ....: for i in range(len(err)): + ....: assert err[i].lift().valuation(p) >= (N - i), \ + ....: "incorrect precision output" """ Rx = F.parent() # Rx = power series ring over Z/p^{N-1} Z R = Rx.base_ring() # R = Z/p^{N-1} Z diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 7ecd6ad8d73..08e167e4691 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -194,7 +194,7 @@ def is_AlgebraicScheme(x): We create a more complicated closed subscheme:: - sage: A, x = AffineSpace(10, QQ).objgens() + sage: A = AffineSpace(10, QQ) sage: X = A.subscheme([sum(x)]); X Closed subscheme of Affine Space of dimension 10 over Rational Field defined by: x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 68366f588f5..3dbcfaf3bf1 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -119,9 +119,10 @@ class SpecialCubicQuotientRing(CommutativeAlgebra): Create elements directly from polynomials:: - sage: A, z = R.poly_ring().objgen() + sage: A = R.poly_ring() sage: A Univariate Polynomial Ring in T over Ring of integers modulo 125 + sage: z = A.gen() sage: R.create_element(z^2, z+1, 3) (T^2) + (T + 1)*x + (3)*x^2 @@ -292,7 +293,8 @@ def create_element(self, p0, p1, p2, check=True): sage: B. = PolynomialRing(Integers(125)) sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4)) - sage: A, z = R.poly_ring().objgen() + sage: A = R.poly_ring() + sage: z = R.gen() sage: R.create_element(z^2, z+1, 3) (T^2) + (T + 1)*x + (3)*x^2 """ diff --git a/src/sage/schemes/plane_curves/affine_curve.py b/src/sage/schemes/plane_curves/affine_curve.py index acc13a6354c..d558c73d73d 100644 --- a/src/sage/schemes/plane_curves/affine_curve.py +++ b/src/sage/schemes/plane_curves/affine_curve.py @@ -237,7 +237,7 @@ def rational_points(self, algorithm="enum"): EXAMPLE:: - sage: A, (x,y) = AffineSpace(2,GF(9,'a')).objgens() + sage: A. = AffineSpace(2,GF(9,'a')) sage: C = Curve(x^2 + y^2 - 1) sage: C Affine Curve over Finite Field in a of size 3^2 defined by x0^2 + x1^2 - 1 diff --git a/src/sage/schemes/plane_quartics/quartic_generic.py b/src/sage/schemes/plane_quartics/quartic_generic.py index c9fcb9169d9..d335d41fe3b 100644 --- a/src/sage/schemes/plane_quartics/quartic_generic.py +++ b/src/sage/schemes/plane_quartics/quartic_generic.py @@ -2,8 +2,9 @@ Plane quartic curves over a general ring. These are generic genus 3 curves, as distinct from hyperelliptic curves of genus 3. -EXAMPLE: - sage: PP, (X,Y,Z) = ProjectiveSpace(2,QQ,'X,Y,Z').objgens() +EXAMPLE:: + + sage: PP. = ProjectiveSpace(2, QQ) sage: f = X^4 + Y^4 + Z^4 - 3*X*Y*Z*(X+Y+Z) sage: C = QuarticCurve(f); C Quartic Curve over Rational Field defined by X^4 + Y^4 - 3*X^2*Y*Z - 3*X*Y^2*Z - 3*X*Y*Z^2 + Z^4 diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index c5bfb8a9d9b..e93e2e90e95 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -27,17 +27,23 @@ Projective Space of dimension 5 over Complex Field with 53 bits of precision The third argument specifies the printing names of the generators -of the homogenous coordinate ring. Using objgens() you can obtain -both the space and the generators as ready to use variables. +of the homogenous coordinate ring. Using the special syntax with +``<`` and ``>>`` you can obtain both the space and the generators as ready to +use variables. :: - sage: P2, (x,y,z) = ProjectiveSpace(2, QQ, 'xyz').objgens() + sage: P2. = ProjectiveSpace(2, QQ) sage: P2 Projective Space of dimension 2 over Rational Field sage: x.parent() Multivariate Polynomial Ring in x, y, z over Rational Field +The first of the three lines above is just equivalent to:: + + sage: P2 = ProjectiveSpace(2, QQ, 'xyz') + sage: x,y,z = P2.gens() + For example, we use `x,y,z` to define the intersection of two lines. @@ -538,7 +544,7 @@ def _linear_system_as_kernel(self, d, pt, m): for col in range(M.ncols()): f = monoms[col][:i] + monoms[col][i+1:] if min([f[j]-e[j] for j in range(n)]) >= 0: - M[row,col] = prod([ binomial(f[j],e[j]) * pt[j]**(f[j]-e[j]) + M[row,col] = prod([ binomial(f[j],e[j]) * pt[j]**(f[j]-e[j]) for j in (k for k in range(n) if f[k] > e[k]) ]) return M diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 0bfa8abf3b4..db1668d8418 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -665,7 +665,7 @@ cdef class CategoryObject(sage_object.SageObject): EXAMPLES:: - sage: R, x = PolynomialRing(QQ,'x',12).objgens() + sage: R, x = PolynomialRing(QQ, 'x', 12).objgens() sage: x (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) sage: print R.latex_variable_names () From 87af2b794e424fd71b68af5d073d48e8d11f78db Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 21:44:52 +0200 Subject: [PATCH 274/665] new doctest, and there is not really such a thing as proper facets --- src/sage/combinat/interval_posets.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 13af75b20f7..512371fd1c0 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -2045,7 +2045,7 @@ def is_new(self): """ Return ``True`` if ``self`` is a new Tamari interval. - Here 'new' means that the interval is not contained in any proper + Here 'new' means that the interval is not contained in any facet of the associahedra. They have been considered in section 9 of [ChapTamari08]_. @@ -2055,6 +2055,10 @@ def is_new(self): sage: TIP4 = TamariIntervalPosets(4) sage: len([u for u in TIP4 if u.is_new()]) 12 + + sage: TIP3 = TamariIntervalPosets(3) + sage: len([u for u in TIP3 if u.is_new()]) + 3 """ c_up = self.upper_binary_tree().single_edge_cut_shapes() c_down = self.lower_binary_tree().single_edge_cut_shapes() From 8a21007e1ee44e1b56364a905fd38c05c27c5541 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 21:46:00 +0200 Subject: [PATCH 275/665] Travis's suggestion --- src/sage/combinat/ribbon_shaped_tableau.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 3e62638736a..08923035bd2 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -452,10 +452,6 @@ def __setstate__(self, state): r""" Unpickle old ``Ribbon_class`` objects. - Due to a bug in the implementation, the result will have parent - :class:`StandardRibbonShapedTableaux`, even if it is not - standard. Rebuild the tableau to get it into the right parent. - EXAMPLES:: sage: loads('x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\xd1+\xcaLJ\xca\xcf\xe3\n\x02S\xf1\xc99\x89\xc5\xc5\\\x85\x8c\x9a\x8d\x85L\xb5\x85\xcc\x1a\xa1\xac\xf1\x19\x89\xc5\x19\x85,~@VNfqI!kl!\x9bFl!\xbb\x06\xc4\x9c\xa2\xcc\xbc\xf4b\xbd\xcc\xbc\x92\xd4\xf4\xd4"\xae\xdc\xc4\xec\xd4x\x18\xa7\x90#\x94\xd1\xb05\xa8\x903\x03\xc80\x022\xb8Rc\x0b\xb95@ Date: Wed, 15 Apr 2015 21:53:53 +0200 Subject: [PATCH 276/665] Trac 18211: use LattE to compute the Ehrhart polynomial --- src/sage/geometry/polyhedron/base_ZZ.py | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 4b1acd05717..2a3f0ac50ee 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -118,6 +118,71 @@ def is_lattice_polytope(self): """ return True + def ehrhart_polynomial(self): + r""" + Return the Ehrhart polynomial of this polyhedron. + + Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP + \cap \ZZ^d)`. Then E. Ehrhart proved in in 1962 that `L` coincide with a + rational polynomial of degree `d` for integer `t`. `L` is called the + *Ehrhart polynomial* of `P`. For more information see + :wikipedia:`Ehrhart_polynomial`. + + ALGORITHM: + + This method calls the program ``count`` from LattE integral, a program + for lattice point enumeration (see + https://www.math.ucdavis.edu/~latte/). + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(0,0,0),(3,3,3),(-3,2,1),(1,-1,-2)]) + sage: p = P.ehrhart_polynomial() # optional - latte_int + sage: p # optional - latte_int + 7/2*t^3 + 2*t^2 - 1/2*t + 1 + sage: p(1) # optional - latte_int + 6 + sage: len(P.integral_points()) + 6 + + The unit hypercubes:: + + sage: from itertools import product + sage: def hypercube(d): + ....: return Polyhedron(vertices=list(product([0,1],repeat=d))) + sage: hypercube(3).ehrhart_polynomial() # optional - latte_int + t^3 + 3*t^2 + 3*t + 1 + sage: hypercube(4).ehrhart_polynomial() # optional - latte_int + t^4 + 4*t^3 + 6*t^2 + 4*t + 1 + sage: hypercube(5).ehrhart_polynomial() # optional - latte_int + t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 + sage: hypercube(6).ehrhart_polynomial() # optional - latte_int + t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 + """ + if not self.is_lattice_polytope(): + raise ValueError("this must be a lattice polytope") + + from sage.misc.package import is_package_installed, package_mesg + if not is_package_installed('latte_int'): + raise ValueError("The package latte_int must be installed!\n" + package_mesg()) + + from sage.misc.temporary_file import tmp_filename + from subprocess import Popen, PIPE + + in_str = self.cdd_Hrepresentation() + in_filename = tmp_filename() + '.ine' + in_file = open(in_filename, 'w') + in_file.write(self.cdd_Hrepresentation()) + in_file.close() + + latte_proc = Popen(['count', '--ehrhart-polynomial', '--cdd', in_filename], + stdin = PIPE, stdout=PIPE, stderr=PIPE) + ans, err = latte_proc.communicate() + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(QQ, 't') + return R(ans) + @cached_method def polar(self): """ From 9c2a4ee7253a43cf5583b722b17ba882731c0b67 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 22:01:49 +0200 Subject: [PATCH 277/665] grammar --- src/sage/combinat/interval_posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 512371fd1c0..159ded1af0a 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -2046,7 +2046,7 @@ def is_new(self): Return ``True`` if ``self`` is a new Tamari interval. Here 'new' means that the interval is not contained in any - facet of the associahedra. + facet of the associahedron. They have been considered in section 9 of [ChapTamari08]_. From 4effeae689f729c99d336cf660ac4de967a4583b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 15 Apr 2015 16:05:44 -0400 Subject: [PATCH 278/665] Deprecating the old iterator but bringing back the contruction as a method. --- src/sage/combinat/alternating_sign_matrix.py | 130 ++++++------------- 1 file changed, 38 insertions(+), 92 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index dac69290aa7..e446c481a25 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -851,10 +851,7 @@ class AlternatingSignMatrices(Parent, UniqueRepresentation): - `n` -- an integer, the size of the matrices. - - ``use_monotone_triangle`` -- (Default: ``True``) If ``True``, the - generation of the matrices uses monotone triangles, else it will use the - earlier and now obsolete contre-tableaux implementation; - must be ``True`` to generate a lattice (with the ``lattice`` method) + - ``use_monotone_triangle`` -- deprecated EXAMPLES: @@ -877,7 +874,7 @@ class AlternatingSignMatrices(Parent, UniqueRepresentation): and Category of finite enumerated sets and Category of facade sets """ - def __init__(self, n, use_monotone_triangles=True): + def __init__(self, n, use_monotone_triangles=None): r""" Initialize ``self``. @@ -885,12 +882,12 @@ def __init__(self, n, use_monotone_triangles=True): sage: A = AlternatingSignMatrices(4) sage: TestSuite(A).run() - sage: A == AlternatingSignMatrices(4, use_monotone_triangles=False) - False """ self._n = n self._matrix_space = MatrixSpace(ZZ, n) - self._umt = use_monotone_triangles + if use_monotone_triangles is not None: + from sage.misc.superseded import deprecation + deprecation(18208, 'use_monotone_triangles is deprecated') Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): @@ -1083,6 +1080,37 @@ def from_height_function(self,height): for i in range(len(list(height)))] for j in range(len(list(height)))] )) + def from_contre_tableau(self, comps): + r""" + Return an alternating sign matrix from a contre-tableau. + + EXAMPLES:: + + sage: ASM = AlternatingSignMatrices(3) + sage: ASM.from_contre_tableau([[1, 2, 3], [1, 2], [1]]) + [0 0 1] + [0 1 0] + [1 0 0] + sage: ASM.from_contre_tableau([[1, 2, 3], [2, 3], [3]]) + [1 0 0] + [0 1 0] + [0 0 1] + """ + n = len(comps) + M = [ [0 for _ in range(n)] for _ in range(n) ] + + previous_set = set([]) + for col in range(n-1, -1, -1): + s = set( comps[col] ) + for x in s.difference(previous_set): + M[x-1][col] = 1 + for x in previous_set.difference(s): + M[x-1][col] = -1 + + previous_set = s + + return AlternatingSignMatrix(M) + def size(self): r""" Return the size of the matrices in ``self``. @@ -1140,21 +1168,8 @@ def __iter__(self): sage: len(list(A)) 42 """ - if self._umt: - for t in MonotoneTriangles(self._n): - yield self.from_monotone_triangle(t) - else: - for c in ContreTableaux(self._n): - yield from_contre_tableau(c) - # This is broken! - # sage: A = AlternatingSignMatrices(3, use_monotone_triangles=False) - # sage: list(A) - # --------------------------------------------------------------------------- - # NameError Traceback (most recent call last) - # ... - # NameError: global name 'from_contre_tableau' is not defined - # If this is really obsolete, the else-branch should be - # removed and the doc modified accordingly. + for t in MonotoneTriangles(self._n): + yield self.from_monotone_triangle(t) def _lattice_initializer(self): r""" @@ -1175,7 +1190,6 @@ def _lattice_initializer(self): sage: P.is_lattice() True """ - assert(self._umt) (mts, rels) = MonotoneTriangles(self._n)._lattice_initializer() bij = dict((t, self.from_monotone_triangle(t)) for t in mts) asms, rels = bij.itervalues(), [(bij[a], bij[b]) for (a,b) in rels] @@ -1429,76 +1443,9 @@ def _is_a_cover(mt0, mt1): return False return diffs == 1 -# Deprecated methods - -def to_monotone_triangle(matrix): - """ - Deprecated method, use :meth:`AlternatingSignMatrix.to_monotone_triangle()` - instead. - - EXAMPLES:: - - sage: sage.combinat.alternating_sign_matrix.to_monotone_triangle([[0,1],[1,0]]) - doctest:...: DeprecationWarning: to_monotone_triangle() is deprecated. Use AlternatingSignMatrix.to_monotone_triangle() instead - See http://trac.sagemath.org/14301 for details. - [[2, 1], [2]] - """ - from sage.misc.superseded import deprecation - deprecation(14301,'to_monotone_triangle() is deprecated. Use AlternatingSignMatrix.to_monotone_triangle() instead') - return AlternatingSignMatrix(matrix).to_monotone_triangle() - -def from_monotone_triangle(triangle): - """ - Deprecated method, use - :meth:`AlternatingSignMatrices.from_monotone_triangle()` instead. - - EXAMPLES:: - - sage: sage.combinat.alternating_sign_matrix.from_monotone_triangle([[1, 2], [2]]) - doctest:...: DeprecationWarning: from_monotone_triangle() is deprecated. Use AlternatingSignMatrix.from_monotone_triangle() instead - See http://trac.sagemath.org/14301 for details. - [0 1] - [1 0] - """ - from sage.misc.superseded import deprecation - deprecation(14301,'from_monotone_triangle() is deprecated. Use AlternatingSignMatrix.from_monotone_triangle() instead') - return AlternatingSignMatrices(len(triangle)).from_monotone_triangle(triangle) - -# For old pickles -def AlternatingSignMatrices_n(n): - """ - For old pickles of ``AlternatingSignMatrices_n``. - - EXAMPLES:: - - sage: sage.combinat.alternating_sign_matrix.AlternatingSignMatrices_n(3) - doctest:...: DeprecationWarning: this class is deprecated. Use sage.combinat.alternating_sign_matrix.AlternatingSignMatrices instead - See http://trac.sagemath.org/14301 for details. - Alternating sign matrices of size 3 - """ - from sage.misc.superseded import deprecation - deprecation(14301,'this class is deprecated. Use sage.combinat.alternating_sign_matrix.AlternatingSignMatrices instead') - return AlternatingSignMatrices(n) - -def MonotoneTriangles_n(n): - """ - For old pickles of ``MonotoneTriangles_n``. - - EXAMPLES:: - - sage: sage.combinat.alternating_sign_matrix.MonotoneTriangles_n(3) - doctest:...: DeprecationWarning: this class is deprecated. Use sage.combinat.alternating_sign_matrix.MonotoneTriangles instead - See http://trac.sagemath.org/14301 for details. - Monotone triangles with 3 rows - """ - from sage.misc.superseded import deprecation - deprecation(14301,'this class is deprecated. Use sage.combinat.alternating_sign_matrix.MonotoneTriangles instead') - return MonotoneTriangles(n) - from sage.structure.sage_object import register_unpickle_override register_unpickle_override('sage.combinat.alternating_sign_matrix', 'AlternatingSignMatrices_n', AlternatingSignMatrices) register_unpickle_override('sage.combinat.alternating_sign_matrix', 'MonotoneTriangles_n', MonotoneTriangles) -register_unpickle_override('sage.combinat.alternating_sign_matrix', 'MonotoneTriangles_n', MonotoneTriangles_n) class ContreTableaux(Parent): """ @@ -1612,7 +1559,6 @@ def __iter__(self): [[1, 2, 3], [2, 3], [2]], [[1, 2, 3], [2, 3], [3]]] """ - for z in self._iterator_rec(self.n): yield z From 09839726d16ef06a51f8acda28aab00d04e4efb4 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 17 Mar 2015 16:41:18 +0100 Subject: [PATCH 279/665] Trac 17971: fix infinite recursion in FractionField_generic._element_constructor_() --- src/sage/rings/fraction_field.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index b02cf89e431..15401922eb4 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -538,6 +538,15 @@ def _element_constructor_(self, x, y=1, coerce=True): Traceback (most recent call last): ... TypeError: unable to evaluate 'z' in Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring + + Check that :trac:`17971` is fixed:: + + sage: A. = Frac(PolynomialRing(QQ,'a,c')) + sage: B. = PolynomialRing(A,'d,e') + sage: R. = PolynomialRing(B,'x') + sage: (a*d*x^2+a+e+1).resultant(-4*c^2*x+1) + a*d + 16*c^4*e + 16*a*c^4 + 16*c^4 + """ Element = self._element_class if isinstance(x, Element) and y == 1: @@ -583,7 +592,7 @@ def _element_constructor_(self, x, y=1, coerce=True): # Below, v is the variable with highest priority, # and the x[i] are rational functions in the # remaining variables. - v = self(x.variable()) + v = Element(self, x.variable(), 1) return sum(self(x[i]) * v**i for i in xrange(x.poldegree() + 1)) raise From 5cc47799992651444a5b29e258dd74f8d44fde2e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 22:28:02 +0200 Subject: [PATCH 280/665] remove obsolete doc --- src/sage/combinat/alternating_sign_matrix.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 10ba62146ac..045dbb675c3 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -1211,10 +1211,6 @@ def __iter__(self): r""" Iterator on the alternating sign matrices of size `n`. - If defined using ``use_monotone_triangles``, this iterator - will use the iteration on the monotone triangles. Else, it - will use the iteration on contre-tableaux. - TESTS:: sage: A = AlternatingSignMatrices(4) From 25a46bd55ef8910b7db050320f3c1f755525ec27 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 15 Apr 2015 22:35:33 +0200 Subject: [PATCH 281/665] some cleanup --- src/sage/combinat/alternating_sign_matrix.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 045dbb675c3..d78350fd756 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -1662,8 +1662,11 @@ def __iter__(self): def _next_column_iterator(previous_column, height, i = None): """ - Returns a generator for all columns of height height properly - filled from row 1 to ``i`` + Return a generator for all columns of height ``height`` + properly filled from row 1 to ``i``. + ("Properly filled" means strictly increasing and having + the property that the `k`-th entry is `\geq` to the `k`-th + entry of ``previous_column`` for each `k`.) EXAMPLES:: @@ -1685,7 +1688,7 @@ def _next_column_iterator(previous_column, height, i = None): if i > 1: min_value = max(min_value, column[i-2]+1) for value in range(min_value, previous_column[i]+1): - c = copy.copy(column) + c = column[:] c[i-1] = value yield c @@ -1823,6 +1826,6 @@ def nw_corner_sum(M,i,j): 4 """ if i >= 0 and j >= 0: - return sum([sum([M[i2][j2] for j2 in range(j)]) for i2 in range(i)]) + return sum([sum(M[i2][:j]) for i2 in range(i)]) return 0 From cf2a10f56ecacf682d57bb355ddfd9980eaee001 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 15 Apr 2015 22:38:44 +0200 Subject: [PATCH 282/665] Trac 18211: another example using Birkhoff_polytope --- src/sage/geometry/polyhedron/library.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 288073b3f75..f2f093f9f9b 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -162,7 +162,7 @@ def regular_polygon(self, n, base_ring=QQ): def Birkhoff_polytope(self, n): """ - Return the Birkhoff polytope with n! vertices. Each vertex + Return the Birkhoff polytope with `n!` vertices. Each vertex is a (flattened) n by n permutation matrix. INPUT: @@ -174,14 +174,25 @@ def Birkhoff_polytope(self, n): sage: b3 = polytopes.Birkhoff_polytope(3) sage: b3.n_vertices() 6 + sage: b3.is_lattice_polytope() + True + sage: p3 = b3.ehrhart_polynomial() # optional - latte_int + 1/8*t^4 + 3/4*t^3 + 15/8*t^2 + 9/4*t + 1 + sage: [p3(i) for i in [1,2,3,4]] # optional - latte_int + [6, 21, 55, 120] + sage: [len((i*b3).integral_points()) for i in [1,2,3,4]] + [6, 21, 55, 120] + + sage: b4 = polytopes.Birkhoff_polytope(4) + sage: b4.n_vertices() == factorial(4) + True """ + from itertools import permutations verts = [] - for p in Permutations(range(1,n+1)): - verts += [ [Polytopes._pfunc(i,j,p) for j in range(1,n+1) - for i in range(1,n+1) ] ] + for p in permutations(range(n)): + verts.append( [int(p[i]==j) for j in range(n) for i in range(n) ] ) return Polyhedron(vertices=verts) - def n_simplex(self, dim_n=3, project = True): """ Return a rational approximation to a regular simplex in From ca8da5a732ca6247cc4ffd375f94f859b6cdf0b1 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 15 Apr 2015 22:40:52 +0200 Subject: [PATCH 283/665] Trac 18211: fixed spelling LattE integral*e* --- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 2a3f0ac50ee..cbd091673a1 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -130,7 +130,7 @@ def ehrhart_polynomial(self): ALGORITHM: - This method calls the program ``count`` from LattE integral, a program + This method calls the program ``count`` from LattE integrale, a program for lattice point enumeration (see https://www.math.ucdavis.edu/~latte/). From d52053c18a593a621af90b43608851304bc32052 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 15 Apr 2015 23:31:05 +0200 Subject: [PATCH 284/665] Trac 18211: check error + options --- src/sage/geometry/polyhedron/base_ZZ.py | 106 ++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index cbd091673a1..affc4cecefb 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -118,7 +118,8 @@ def is_lattice_polytope(self): """ return True - def ehrhart_polynomial(self): + def ehrhart_polynomial(self, dual=None, irrational_primal=None, + irrational_all_primal=None, maxdet=None, verbose=False): r""" Return the Ehrhart polynomial of this polyhedron. @@ -128,6 +129,25 @@ def ehrhart_polynomial(self): *Ehrhart polynomial* of `P`. For more information see :wikipedia:`Ehrhart_polynomial`. + INPUT: + + - ``dual`` - (boolean) triangulate and signed-decompose in the dual + space + + - ``irrational_primal`` - (boolean) triangulate in the dual space, + signed-decompose in the primal space using irrationalization + + - ``irrational_all_primal`` - (boolean) Triangulate and signed-decompose + in the primal space using irrationalization + + - ``maxdet`` -- (integer) decompose down to an index (determinant) of + ``maxdet`` instead of index 1 (unimodular cones) + + - ``no_decomposition`` -- do not signed-decompose simplicial cones + + - ``verbose`` - (boolean, default to ``False``) if ``True``, print the + whole output of the LattE command + ALGORITHM: This method calls the program ``count`` from LattE integrale, a program @@ -144,6 +164,10 @@ def ehrhart_polynomial(self): 6 sage: len(P.integral_points()) 6 + sage: p(2) # optional - latte_int + 36 + sage: len((2*P).integral_points()) + 36 The unit hypercubes:: @@ -158,6 +182,49 @@ def ehrhart_polynomial(self): t^5 + 5*t^4 + 10*t^3 + 10*t^2 + 5*t + 1 sage: hypercube(6).ehrhart_polynomial() # optional - latte_int t^6 + 6*t^5 + 15*t^4 + 20*t^3 + 15*t^2 + 6*t + 1 + + An empty polyhedron:: + + sage: P = Polyhedron(ambient_dim=3, vertices=[]) + sage: P.ehrhart_polynomial() # optional - latte_int + 0 + sage: parent(_) + Univariate Polynomial Ring in t over Rational Field + + Test options:: + + sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ) + + sage: p = P.ehrhart_polynomial(maxdet=5, verbose=True) # optional - latte_int + This is LattE integrale 1.7.2 + ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' '--maxdet=5' --cdd ... + ... + sage: p # optional - latte_int + 1/2*t^2 + 3/2*t + 1 + + sage: p = P.ehrhart_polynomial(dual=True, verbose=True) # optional - latte_int + This is LattE integrale 1.7.2 + ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' --dual --cdd ... + ... + sage: p # optional - latte_int + 1/2*t^2 + 3/2*t + 1 + + sage: p = P.ehrhart_polynomial(irrational_primal=True, verbose=True) # optional - latte_int + This is LattE integrale 1.7.2 + ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational_primal --cdd ... + ... + sage: p # optional - latte_int + 1/2*t^2 + 3/2*t + 1 + + sage: p = P.ehrhart_polynomial(irrational_all_primal=True, verbose=True) # optional - latte_int + This is LattE integrale 1.7.2 + ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational_all_primal --cdd ... + sage: p # optional - latte_int + 1/2*t^2 + 3/2*t + 1 """ if not self.is_lattice_polytope(): raise ValueError("this must be a lattice polytope") @@ -166,6 +233,11 @@ def ehrhart_polynomial(self): if not is_package_installed('latte_int'): raise ValueError("The package latte_int must be installed!\n" + package_mesg()) + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(QQ, 't') + if self.is_empty(): + return R.zero() + from sage.misc.temporary_file import tmp_filename from subprocess import Popen, PIPE @@ -175,13 +247,33 @@ def ehrhart_polynomial(self): in_file.write(self.cdd_Hrepresentation()) in_file.close() - latte_proc = Popen(['count', '--ehrhart-polynomial', '--cdd', in_filename], - stdin = PIPE, stdout=PIPE, stderr=PIPE) + args = ['count', '--ehrhart-polynomial', '--redundancy-check=none'] + if dual: + args.append('--dual') + if irrational_primal: + args.append('--irrational_primal') + if irrational_all_primal: + args.append('--irrational_all_primal') + if maxdet: + maxdet = int(maxdet) + if maxdet < 0: + raise ValueError("maxdet must be a positive integer") + args.append('--maxdet={}'.format(maxdet)) + + args.append('--cdd') + args.append(in_filename) + + latte_proc = Popen(args, stdin = PIPE, stdout=PIPE, stderr=PIPE) ans, err = latte_proc.communicate() - - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(QQ, 't') - return R(ans) + ret_code = latte_proc.poll() + if ret_code: + raise ValueError("LattE program 'count' ended with a nonzero value" + "(={}). Here is the content of stderr:\n{}".format( + ret_code, err)) + if verbose: + print err + + return R(ans.splitlines()[-2]) @cached_method def polar(self): From 0f5122bddee5f104a3e2ff65715129eb275452e7 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 15 Apr 2015 23:59:33 +0200 Subject: [PATCH 285/665] Trac 18211: fix command line arguments --- src/sage/geometry/polyhedron/base_ZZ.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index affc4cecefb..dab2e0e0bea 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -119,7 +119,7 @@ def is_lattice_polytope(self): return True def ehrhart_polynomial(self, dual=None, irrational_primal=None, - irrational_all_primal=None, maxdet=None, verbose=False): + irrational_all_primal=None, maxdet=None, no_decomposition=None, verbose=False): r""" Return the Ehrhart polynomial of this polyhedron. @@ -135,18 +135,18 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, space - ``irrational_primal`` - (boolean) triangulate in the dual space, - signed-decompose in the primal space using irrationalization + signed-decompose in the primal space using irrationalization. - ``irrational_all_primal`` - (boolean) Triangulate and signed-decompose - in the primal space using irrationalization + in the primal space using irrationalization. - ``maxdet`` -- (integer) decompose down to an index (determinant) of - ``maxdet`` instead of index 1 (unimodular cones) + ``maxdet`` instead of index 1 (unimodular cones). - - ``no_decomposition`` -- do not signed-decompose simplicial cones + - ``no_decomposition`` -- (boolean) do not signed-decompose simplicial cones. - ``verbose`` - (boolean, default to ``False``) if ``True``, print the - whole output of the LattE command + whole output of the LattE command. ALGORITHM: @@ -214,7 +214,7 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, sage: p = P.ehrhart_polynomial(irrational_primal=True, verbose=True) # optional - latte_int This is LattE integrale 1.7.2 ... - Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational_primal --cdd ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational-primal --cdd ... ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 @@ -222,7 +222,7 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, sage: p = P.ehrhart_polynomial(irrational_all_primal=True, verbose=True) # optional - latte_int This is LattE integrale 1.7.2 ... - Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational_all_primal --cdd ... + Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational-all-primal --cdd ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 """ @@ -251,14 +251,16 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, if dual: args.append('--dual') if irrational_primal: - args.append('--irrational_primal') + args.append('--irrational-primal') if irrational_all_primal: - args.append('--irrational_all_primal') + args.append('--irrational-all-primal') if maxdet: maxdet = int(maxdet) if maxdet < 0: raise ValueError("maxdet must be a positive integer") args.append('--maxdet={}'.format(maxdet)) + if no_decomposition: + args.append('--no-decomposition') args.append('--cdd') args.append(in_filename) From 0aa8bb15e816f904bfff506453b7ef5721806a70 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 15 Apr 2015 17:56:27 -0700 Subject: [PATCH 286/665] work on modular characteristic --- .../root_system/integrable_representations.py | 169 +++++++++++++++--- 1 file changed, 140 insertions(+), 29 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index e8b45115709..ad539c78ed0 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -156,26 +156,17 @@ def __init__(self, Lam): self._cartan_matrix = self._P.root_system.cartan_matrix() self._cartan_type = self._P.root_system.cartan_type() + if not self._cartan_type.is_untwisted_affine(): + raise NotImplementedError("Integrable Representations are only implemented for Untwisted Affine Types.") self._classical_rank = self._cartan_type.classical().rank() self._index_set = self._P.index_set() self._index_set_classical = self._cartan_type.classical().index_set() self._cminv = self._cartan_type.classical().cartan_matrix().inverse() - self._smat = {} - for i in self._index_set: - for j in self._index_set: - self._smat[(i,j)] = -self._cartan_matrix[i,j] - self._smat[(i,i)] += 1 - - self._shift = {} - alphacheck = self._Q.simple_coroots() - for i in self._index_set: - self._shift[i] = self._Lam.scalar(alphacheck[i]) - self._ddict = {} self._mdict = {tuple(0 for i in self._index_set): 1} self._rho = self._P.rho() - + self._delta = self._Q.null_root() # Coerce a classical root into Q from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) self._classical_roots = [from_cl_root(al) @@ -186,6 +177,8 @@ def __init__(self, Lam): for i in self._index_set} self._a = self._cartan_type.a() self._ac = self._cartan_type.dual().a() + self._coxeter_number = sum(self._a[i] for i in self._index_set) + self._dual_coxeter_number = sum(self._ac[i] for i in self._index_set) E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical]) self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse() self._den0 = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho) @@ -193,6 +186,13 @@ def __init__(self, Lam): def highest_weight(self): """ Returns the highest weight of the IntegrableRepresentation ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(Lambda[0]+2*Lambda[2]).highest_weight() + Lambda[0] + 2*Lambda[2] + """ return self._Lam @@ -214,7 +214,7 @@ def root_lattice(self): Returns the Root Lattice of ``self``. EXAMPLES:: - sage: v=IntegrableRepresentation(RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: v=IntegrableRepresentation(RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weight(0)) sage: v.root_lattice() Root lattice of the Root system of type ['F', 4, 1] @@ -226,12 +226,62 @@ def null_root(self): Returns the nullroot of ``self``. EXAMPLES:: + sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v=IntegrableRepresentation(Lambda[0]) sage: delta = v.null_root(); delta alpha[0] + 3*alpha[1] + 2*alpha[2] """ - return self._Q.null_root() + return self._delta + + def rho(self): + """ + Returns the Weyl vector `\\rho`. + + EXAMPLES:: + + sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(Lambda[0]).rho() + Lambda[0] + Lambda[1] + Lambda[2] + """ + return self._rho + + def level(self): + """ + The level of the representation equals `(\\rho|\delta)`. See [Kac] section 12.4. + + """ + return self._inner_pq(self._Lam, self._delta) + + def coxeter_number(self): + """ + The dual Coxeter number is defined in [Kac] Chapter 6, and commonly + denoted `h`. + + EXAMPLES:: + + sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: v.coxeter_number() + 12 + + """ + return self._coxeter_number + + def dual_coxeter_number(self): + """ + The dual Coxeter number is defined in [Kac] Chapter 6, and commonly + denoted `h^\\vee`. + + EXAMPLES:: + + sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: v.dual_coxeter_number() + 9 + + """ + return self._dual_coxeter_number def __repr__(self): """ @@ -339,11 +389,22 @@ def _inner_pp(self, pelt1, pelt2): def to_weight(self, n): """ - Return the weight associated to the tuple ``n``. + INPUT: + + - ``n`` -- a tuple representing a weight. + + Returns the weight associated to the tuple ``n``. If ``n`` + is the tuple `(n_1, n_2, \ldots)`, then the associated + weight is `\Lambda - sum_i n_i \alpha_i`, where `\Lambda` + is the weight of the representation. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[2]) + sage: v.to_weight((1,0,0)) + -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta - If ``n`` is the tuple `(n_1, n_2, \ldots)`, then the associated - weight is `\Lambda - sum_i n_i \alpha_i`, where `\Lambda` is the - weight of the representation. """ alpha = self._P.simple_roots() I = self._index_set @@ -378,6 +439,17 @@ def _from_weight_helper(self, mu): def from_weight(self, mu): """ Return ``(n[0], n[1], ...)`` such that ``mu = Lam - sum n[i]*alpha[i]`` + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[2]) + sage: v.to_weight((1,0,0)) + -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta + sage: delta = v.null_root() + sage: v.from_weight(-2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta) + (1, 0, 0) + """ return self._from_weight_helper(self._Lam - mu) @@ -430,7 +502,7 @@ def to_dominant(self, n): self._ddict[m] = v return v - def freudenthal_roots_imaginary(self, nu): + def _freudenthal_roots_imaginary(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of imaginary roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. @@ -440,7 +512,7 @@ def freudenthal_roots_imaginary(self, nu): delta = self._Q.null_root() return [u*delta for u in range(1, kp+1)] - def freudenthal_roots_real(self, nu): + def _freudenthal_roots_real(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of real positive roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. @@ -450,7 +522,7 @@ def freudenthal_roots_real(self, nu): if all(x >= 0 for x in self._from_weight_helper(nu-al)): ret.append(al) for al in self._classical_roots: - for ir in self.freudenthal_roots_imaginary(nu-al): + for ir in self._freudenthal_roots_imaginary(nu-al): ret.append(al+ir) return ret @@ -462,9 +534,9 @@ def freudenthal_roots(self, nu): This code is not called in the main algorithm. """ ret = [] - for alpha in self.freudenthal_roots_imaginary(nu): + for alpha in self._freudenthal_roots_imaginary(nu): ret.append(alpha) - for alpha in self.freudenthal_roots_real(nu): + for alpha in self._freudenthal_roots_real(nu): ret.append(alpha) return ret @@ -500,9 +572,9 @@ def _m_freudenthal(self, n): remove_zeros=False) den = 2*self._inner_pq(self._Lam+self._P.rho(), al) - self._inner_qq(al, al) num = 0 - for al in self.freudenthal_roots_real(self._Lam - mu): + for al in self._freudenthal_roots_real(self._Lam - mu): num += self._freudenthal_accum(mu, al) - for al in self.freudenthal_roots_imaginary(self._Lam - mu): + for al in self._freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank * self._freudenthal_accum(mu, al) if den == 0 and num == 0: print "_m_freudenthal","m: n=%s, num=den=0"%n.__repr__() @@ -518,14 +590,13 @@ def m(self, n): - ``n`` -- a representing a weight `\mu`. Return the multiplicity of the weight `\mu` in ``self``, where - `\mu = \Lambda - \sum_i n[i]\,\alpha_i``. + `\mu = \Lambda - \sum_i n_i \\alpha_i`. EXAMPLES:: sage: Lambda = RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(Lambda[0]) - sage: u = v.highest_weight()-v.null_root(); u - Lambda[0] - delta + sage: u = v.highest_weight()-v.null_root() sage: v.from_weight(u) (1, 1, 2, 2, 3, 2, 1) sage: v.m(v.from_weight(u)) @@ -554,7 +625,7 @@ def m(self, n): #@lazy_attribute def dominant_maximal(self): """ - Return the finite set of dominant maximal weights. + Find the finite set of dominant maximal weights. """ ret = set() delta = self._Q.null_root() @@ -616,3 +687,43 @@ def strings(self, depth=12): print j, print + def modular_characteristic(self, n=None): + """ + OPTIONAL: + + - ``mu`` -- + + The modular characteristic is a rational number introduced + by Kac and Peterson (1984), required to interpret the string + functions as Fourier coefficients of modular forms. See + [Kac] Section 12.7. Let `k` be the level, and let `h^\\vee` + be the dual Coxeter number. Then + + .. MATH:: + + m_\Lambda = \\frac{|\Lambda+\\rho|^2}{2(k+h^\\vee)} - \\frac{|\\rho|^2}{2h^\\vee} + + If $\mu$ is a weight, then + + .. MATH:: + + m_{\Lambda,\mu} = m_\Lambda - \\frac{|\mu|^2}{2k}. + + OPTIONAL: + + - ``n`` -- a tuple representing a weight `\mu`. + + The weight `\mu` is `\Lambda - \sum_i n_i \\alpha_i`. The function + returns `m_\Lambda` if `n` is omitted, otherwise it returns + `m_{\Lambda,\mu}`. + + """ + k = self.level() + hd = self._dual_coxeter_number + m_Lambda = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho)/(2*(k+hd)) - \ + self._inner_pp(self._rho,self._rho)/(2*hd) + if n is None: + return m_Lambda + else: + mu = self.to_weight(n) + return m_Lambda-self._inner_pp(mu,mu)/(2*k) From b7ff9d26c8a40b1ff40ca17328bcea55294135b6 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Thu, 16 Apr 2015 02:46:01 +0000 Subject: [PATCH 287/665] 11111: improvements to the documentation --- src/sage/combinat/free_module.py | 18 +++--- src/sage/combinat/symmetric_group_algebra.py | 2 +- src/sage/modules/with_basis/subquotient.py | 58 +++++++++++--------- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 50dda7422f4..24cd7f85b8f 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1590,11 +1590,11 @@ def set_order(self, order): the one used in the generation of the elements of self's associated enumerated set. - .. warning:: many cached methods depend on this order, in - particular for constructing subspaces and - quotients. Changing the order after computing such does - currently not invalidate those cache, and is likely to - bring in inconsistencies. + .. warning:: Many cached methods depend on this order, in + particular for constructing subspaces and quotients. + Changing the order after some computations have been + cached does not invalidate the cache, and is likely to + introduce inconsistencies. EXAMPLES:: @@ -1626,7 +1626,7 @@ def get_order(self): def get_order_cmp(self): """ - Returns a comparison function on the basis indices which is + Returns a comparison function on the basis indices that is compatible with the current term order. EXAMPLES:: @@ -2068,15 +2068,15 @@ def echelon_form(self, elements, base_ring=None): INPUT: - ``elements`` - a list of elements of ``self``. - + - ``base_ring`` - ring (default: ``None``): compute the echelon form over the given ring; if ``base_ring`` is ``None``, then uses the base ring of ``self``. OUTPUT: - + - list of elements of ``self`` - + EXAMPLES:: sage: F = CombinatorialFreeModule(ZZ, [1,2,3,4]) diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 4eac700f8cc..c3c05b70b27 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -191,7 +191,7 @@ def SymmetricGroupAlgebra(R, W): True sage: TestSuite(SGA).run() - sage: SG=SymmetricGroupAlgebra(ZZ,3) + sage: SG = SymmetricGroupAlgebra(ZZ, 3) sage: SG.group().conjugacy_classes_representatives() [[1, 2, 3], [2, 1, 3], [2, 3, 1]] diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index dd0fe21e615..12b15410631 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -2,7 +2,7 @@ Quotients of Modules With Basis """ #***************************************************************************** -# Copyright (C) 2010 Florent Hivert +# Copyright (C) 2010-2015 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -26,7 +26,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): should implement a method ``reduce``. Futheremore its ``lift`` method should have a method ``.cokernel_basis_indices`` that computes the indexing set of a subset of the basis of ``self`` - that spans some suplementary of ``submodule`` in the ambient + that spans some supplementary of ``submodule`` in the ambient space. Mathematically speaking, ``submodule`` should be a free submodule whose basis can be put in unitriangular echelon form. @@ -57,7 +57,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): @staticmethod def __classcall_private__(cls, submodule, category=None): r""" - Normalize the input + Normalize the input. TESTS:: @@ -76,18 +76,21 @@ def __classcall_private__(cls, submodule, category=None): def __init__(self, submodule, category): r""" + Initialization quotients of a module with basis by a submodule. + TESTS:: sage: from sage.modules.with_basis.subquotient import QuotientModuleWithBasis - sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: I = X.submodule( (x[0]-x[1], x[1]-x[2]) ) sage: Y = QuotientModuleWithBasis(I) + sage: Y.print_options(prefix='y') sage: Y Free module generated by {2} over Rational Field sage: Y.category() Join of Category of finite dimensional modules with basis over Rational Field and Category of vector spaces with basis over Rational Field and Category of quotients of sets sage: Y.basis().list() - [B[2]] + [y[2]] sage: TestSuite(Y).run() """ self._submodule = submodule @@ -104,7 +107,7 @@ def ambient(self): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])) sage: Y.ambient() is X True @@ -112,7 +115,7 @@ def ambient(self): return self._ambient def lift(self, x): - """ + r""" Lift ``x`` to the ambient space of ``self``. INPUT: @@ -121,8 +124,8 @@ def lift(self, x): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() - sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() + sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.lift(y[2]) x[2] """ @@ -139,8 +142,8 @@ def retract(self, x): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3), prefix = "x"); x = X.basis() - sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() + sage: Y = X.quotient_module((x[0]-x[1], x[1]-x[2])); y = Y.basis() sage: Y.print_options(prefix='y') sage: Y.retract(x[0]) y[2] @@ -159,7 +162,7 @@ class SubmoduleWithBasis(CombinatorialFreeModule): INPUT: - - ``basis`` -- a family of vectors in echelon form in some + - ``basis`` -- a family of elements in echelon form in some :class:`module with basis ` `V`, or data that can be converted into such a family @@ -196,7 +199,7 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts basis = Family(basis) if ambient is None: ambient = basis.an_element().parent() - default_category=ModulesWithBasis(ambient.category().base_ring()).Subobjects() + 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) @@ -208,13 +211,14 @@ def __init__(self, basis, ambient, category): TESTS:: sage: from sage.modules.with_basis.subquotient import SubmoduleWithBasis - sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + 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.print_options(prefix='y') sage: Y.basis().list() - [B[0], B[1]] + [y[0], y[1]] sage: [ y.lift() for y in Y.basis() ] - [B[0] - B[1], B[1] - B[2]] + [x[0] - x[1], x[1] - x[2]] sage: TestSuite(Y).run() """ import operator @@ -245,20 +249,21 @@ def lift(self): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True); y = Y.basis() sage: Y.lift Generic morphism: From: Free module generated by {0, 1} over Rational Field To: Free module generated by {0, 1, 2} over Rational Field sage: [ Y.lift(u) for u in y ] - [B[0] - B[1], B[1] - B[2]] + [x[0] - x[1], x[1] - x[2]] sage: (y[0] + y[1]).lift() - B[0] - B[2] + x[0] - x[2] """ return self.module_morphism(self.lift_on_basis, codomain=self.ambient(), - triangular="lower", cmp=self.ambient().get_order_cmp(), + triangular="lower", + cmp=self.ambient().get_order_cmp(), inverse_on_support="compute") @lazy_attribute @@ -271,14 +276,14 @@ def reduce(self): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) sage: Y.reduce Generic endomorphism of Free module generated by {0, 1, 2} over Rational Field sage: Y.reduce(x[1]) - B[2] + x[2] sage: Y.reduce(2*x[0] + x[1]) - 3*B[2] + 3*x[2] TESTS:: @@ -294,14 +299,15 @@ def retract(self): EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: Y = X.submodule((x[0]-x[1], x[1]-x[2]), already_echelonized=True) + sage: Y.print_options(prefix='y') sage: Y.retract Generic morphism: From: Free module generated by {0, 1, 2} over Rational Field To: Free module generated by {0, 1} over Rational Field sage: Y.retract(x[0] - x[2]) - B[0] + B[1] + y[0] + y[1] TESTS:: @@ -334,7 +340,7 @@ def is_submodule(self, other): if other is self.ambient(): return True if not isinstance(self, SubmoduleWithBasis) and self.ambient() is other.ambient(): - raise ValueError("other (=%s) should be a submodule of the same ambient space"%other) + raise ValueError("other (=%s) should be a submodule of the same ambient space" % other) if not self in ModulesWithBasis.FiniteDimensional: raise NotImplementedError("is_submodule for infinite dimensional modules") for b in self.basis(): From a12db779288e6a65fa1cf95f18e19ed84058be1b Mon Sep 17 00:00:00 2001 From: "R. Andrew Ohana" Date: Wed, 15 Apr 2015 19:48:38 -0700 Subject: [PATCH 288/665] remove gdmodule --- COPYING.txt | 14 ---- build/deps | 9 +-- build/install | 1 - build/pkgs/gdmodule/SPKG.txt | 52 ------------- build/pkgs/gdmodule/checksums.ini | 4 - build/pkgs/gdmodule/package-version.txt | 1 - build/pkgs/gdmodule/patches/Setup.py.patch | 76 ------------------- build/pkgs/gdmodule/patches/_gdmodule.c.patch | 34 --------- build/pkgs/gdmodule/spkg-install | 33 -------- 9 files changed, 2 insertions(+), 222 deletions(-) delete mode 100644 build/pkgs/gdmodule/SPKG.txt delete mode 100644 build/pkgs/gdmodule/checksums.ini delete mode 100644 build/pkgs/gdmodule/package-version.txt delete mode 100644 build/pkgs/gdmodule/patches/Setup.py.patch delete mode 100644 build/pkgs/gdmodule/patches/_gdmodule.c.patch delete mode 100755 build/pkgs/gdmodule/spkg-install diff --git a/COPYING.txt b/COPYING.txt index 2e9fd63535b..fe0873054d8 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -54,7 +54,6 @@ freetype FreeType License (similar to BSD; see below) gap GPLv2+ gcc GPLv3+ gd Custom (BSD-ish) -gdmodule Custom (BSD-ish) genus2reduction GPLv2+ gfan GPLv2 or GPLv3 gf2x GPLv2+ @@ -949,19 +948,6 @@ documentation. ================================================================================ -gdmodule: -(http://newcenturycomputers.net/projects/gdmodule.html) - -Permission granted for unlimited use, provided that the Quest Center -at Cold Spring Harbor Labs is given credit for the library in the -user-visible documentation of your software. If you modify gd, we ask -that you share the modifications with us so they can be added to the -distribution. See gd.html for details. (The rest of the notice is in -the package gdmodule spkg, which is a bzip2'd tarball included in the -Sage source distribution.) - -================================================================================ - genus2reduction: (http://www.math.u-bordeaux.fr/~liu/G2R/) Copyright Qing LIU. See PARI for the license terms. diff --git a/build/deps b/build/deps index ce22da50bb1..b076a835cda 100644 --- a/build/deps +++ b/build/deps @@ -47,7 +47,6 @@ all-sage: \ $(INST)/$(FREETYPE) \ $(INST)/$(GAP) \ $(INST)/$(GD) \ - $(INST)/$(GDMODULE) \ $(INST)/$(GFAN) \ $(INST)/$(GF2X) \ $(INST)/$(GIVARO) \ @@ -329,9 +328,6 @@ $(INST)/$(PEXPECT): $(INST)/$(PYTHON) $(INST)/$(GD): $(INST)/$(LIBPNG) $(INST)/$(FREETYPE) $(INST)/$(ICONV) +$(PIPE) "$(SAGE_SPKG) $(GD) 2>&1" "tee -a $(SAGE_LOGS)/$(GD).log" -$(INST)/$(GDMODULE): $(INST)/$(PYTHON) $(INST)/$(GD) $(INST)/$(ICONV) - +$(PIPE) "$(SAGE_SPKG) $(GDMODULE) 2>&1" "tee -a $(SAGE_LOGS)/$(GDMODULE).log" - $(INST)/$(SCONS): $(INST)/$(PYTHON) +$(PIPE) "$(SAGE_SPKG) $(SCONS) 2>&1" "tee -a $(SAGE_LOGS)/$(SCONS).log" @@ -406,9 +402,8 @@ $(INST)/$(MATHJAX): $(INST)/$(MATPLOTLIB): $(INST)/$(PYTHON) $(INST)/$(NUMPY) \ $(INST)/$(FREETYPE) $(INST)/$(LIBPNG) \ - $(INST)/$(GDMODULE) $(INST)/$(DATEUTIL) \ - $(INST)/$(PYPARSING) $(INST)/$(SETUPTOOLS) \ - $(INST)/$(TORNADO) $(INST)/$(SIX) + $(INST)/$(DATEUTIL) $(INST)/$(PYPARSING) \ + $(INST)/$(SETUPTOOLS) $(INST)/$(TORNADO) $(INST)/$(SIX) +$(PIPE) "$(SAGE_SPKG) $(MATPLOTLIB) 2>&1" "tee -a $(SAGE_LOGS)/$(MATPLOTLIB).log" $(INST)/$(CDDLIB): $(INST)/$(SAGE_MP_LIBRARY) diff --git a/build/install b/build/install index f66dfd21fe5..5ac25d39d38 100755 --- a/build/install +++ b/build/install @@ -322,7 +322,6 @@ FREETYPE=`newest_version freetype` GAP=`newest_version gap` GCC=`newest_version gcc` GD=`newest_version libgd` -GDMODULE=`newest_version gdmodule` GFAN=`newest_version gfan` GF2X=`newest_version gf2x` GIT=`newest_version git` diff --git a/build/pkgs/gdmodule/SPKG.txt b/build/pkgs/gdmodule/SPKG.txt deleted file mode 100644 index ed2d44c51ed..00000000000 --- a/build/pkgs/gdmodule/SPKG.txt +++ /dev/null @@ -1,52 +0,0 @@ -= gdmodule = - -== Description == - -From http://newcenturycomputers.net/projects/gdmodule.html: The GDmodule is an interface to the GD library written by Thomas Boutell. 'gd is a graphics library. It allows your code to quickly draw images complete with lines, arcs, text, multiple colors, cut and paste from other images, and flood fills, and write out the result as a PNG or JPEG file. This is particularly useful in World Wide Web applications, where PNG and JPEG are two of the formats accepted for inline images by most browsers.' - -== License == - -BSD: "COPYRIGHT 1994 BY THE QUEST CENTER AT COLD SPRING HARBOR LABS. -Permission granted for unlimited use, provided that the Quest Center at Cold Spring Harbor Labs is given credit for the library in the user-visible documentation of your software. If you modify gd, we ask that you share the modifications with us so they can be added to the distribution. See gd.html for details. - -== SPKG Maintainers == - - * None - -== Upstream Contact == - - * See http://newcenturycomputers.net/projects/gdmodule.html for contact information. - -== Dependencies == - - * GNU patch - * Python - * libpng - * gd - * iconv - -== Special Update/Build Instructions == - - * Patch Setup.py: we link against libpng12 instead of libpng. There - are also changes to the library handling on Cygwin, so this might - need to be fixed. Remove non-system include and library prefixes - /sw and /usr/local. If a different version of GD is installed - in one of these directories, the gdmodule installer gets in trouble. - -== Changelog == - -=== gdmodule-0.56.p8 (Robert Bradshaw, Jeroen Demeyer, 6 May 2012) === - * Trac #12909: Setup.py: don't use non-system prefixes - /sw and /usr/local to look for include files or libraries. - * Use standard template for spkg-install, use patch for patching. - * Restore upstream sources. The pre-existing changes to src/Setup.py - have been moved to Setup.py.patch - * _gdmodule.c: Undo change of #include to #include "gd.h" - -=== gdmodule-0.56.p7 (Mike Hansen, October 27th, 2009) === - * Make gdmodule work on Cygwin. - -=== gdmodule-0.56.p5 (Michael Abshoff) === - * add .hgignore, SPKG.txt - * clean up patches directory - * build gdmodule against libpng12 instead of libpng (#5289) diff --git a/build/pkgs/gdmodule/checksums.ini b/build/pkgs/gdmodule/checksums.ini deleted file mode 100644 index f48694169bc..00000000000 --- a/build/pkgs/gdmodule/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=gdmodule-VERSION.tar.bz2 -sha1=ee2cdca51356dfab9e028faa12b00d50a33711a4 -md5=f944f09ffba0b73992c27b9c1ec710a5 -cksum=157875398 diff --git a/build/pkgs/gdmodule/package-version.txt b/build/pkgs/gdmodule/package-version.txt deleted file mode 100644 index 54c3cc4e12e..00000000000 --- a/build/pkgs/gdmodule/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.56.p8 diff --git a/build/pkgs/gdmodule/patches/Setup.py.patch b/build/pkgs/gdmodule/patches/Setup.py.patch deleted file mode 100644 index 922bba052b2..00000000000 --- a/build/pkgs/gdmodule/patches/Setup.py.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff -ru src/Setup.py b/Setup.py ---- src/Setup.py 2005-03-11 05:29:59.000000000 +0100 -+++ b/Setup.py 2012-05-06 00:54:31.893372094 +0200 -@@ -40,7 +40,8 @@ - # Unixoid OS's I will just look for the usual suspects. - - libdirs = dirtest([ -- "/usr/local/lib", "/sw/lib", "/usr/lib", -+ os.environ["SAGE_LOCAL"]+"/lib", -+ "/usr/lib", - "/usr/lib/X11", "/usr/X11R6/lib", - "/opt/gnome/lib", - ]) -@@ -48,21 +49,25 @@ - # include_dirs are also non-portable; same trick here. - - incdirs = dirtest([ -- "/usr/local/include", "/sw/include", "/usr/include", -+ os.environ["SAGE_LOCAL"]+"/include", -+ "/usr/include", - "/usr/include/X11", "/usr/X11R6/include", - "/opt/gnome/include", - ]) - - # Try to identify our libraries - --want_libs = [ -- "gd", -- "jpeg", "png", "gif", "z", -- "X11", "Xpm", -- "ttf", "freetype", --] -- --libs = filetest(libdirs, want_libs) -+import os -+if os.uname()[0][:6] == "CYGWIN": -+ want_libs = [ -+ "gd", "png12", "z", "freetype", "iconv", "fontconfig", -+ ] -+ libs = filetest(libdirs, want_libs) -+else: -+ want_libs = [ -+ "gd", "png12", "z", "freetype" -+ ] -+ libs = filetest(libdirs, want_libs) - - missing = [] - -@@ -85,18 +90,22 @@ - if "Xpm" in libs and "X11" not in libs: - remove("Xpm", libs) - --if "png" in libs and "z" not in libs: -- remove("png", libs) -+if "png12" in libs and "z" not in libs: -+ remove("png12", libs) - --if "z" in libs and "png" not in libs: -- remove("png", libs) -+if "z" in libs and "png12" not in libs: -+ remove("png12", libs) - - # build the macro list - - macros = [] - - for l in libs: -- macros.append(( "HAVE_LIB%s" % l.upper(), None )) -+ if l == "png12": -+ macros.append(( "HAVE_LIBPNG", None )) -+ else: -+ macros.append(( "HAVE_LIB%s" % l.upper(), None )) -+ - - # OK, now do it! - diff --git a/build/pkgs/gdmodule/patches/_gdmodule.c.patch b/build/pkgs/gdmodule/patches/_gdmodule.c.patch deleted file mode 100644 index 868d847de14..00000000000 --- a/build/pkgs/gdmodule/patches/_gdmodule.c.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -ru src/_gdmodule.c c/_gdmodule.c ---- src/_gdmodule.c 2005-03-11 06:06:26.000000000 +0100 -+++ c/_gdmodule.c 2012-05-06 00:59:07.453373313 +0200 -@@ -346,12 +346,12 @@ - return write_file(self, args, 'p'); - } - -- -+#ifdef HAVE_LIBJPEG - static PyObject *image_writejpeg(imageobject *self, PyObject *args) - { - return write_file(self, args, 'j'); - } -- -+#endif - - static PyObject *image_writegd(imageobject *self, PyObject *args) - { -@@ -1420,13 +1420,13 @@ - "writePng(f)\n" - "write the image to f as a PNG, where f is either an open file object or a\n" - "file name."}, -- -+#ifdef HAVE_LIBJPEG - {"writeJpeg", (PyCFunction)image_writejpeg, 1, - "writeJpeg(f,quality)\n" - "write the image to f as a JPEG, where f is either an open file object or a\n" - "file name. quality is an optional integer value giving the JPEG quality from\n" - "0 to 95%; leave out for default quality."}, -- -+#endif - {"writeWbmp", (PyCFunction)image_writewbmp, 1, - "writeWbmp(f,fg)\n" - "write the image to f as a WBMP, where f is either an open file object or a\n" diff --git a/build/pkgs/gdmodule/spkg-install b/build/pkgs/gdmodule/spkg-install deleted file mode 100755 index 809afee4b1d..00000000000 --- a/build/pkgs/gdmodule/spkg-install +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -cd src - -# Apply patches. -for patch in ../patches/*.patch; do - patch -p1 <"$patch" - if [ $? -ne 0 ]; then - echo >&2 "Error applying '$patch'" - exit 1 - fi -done - -# Now build and install. -python Setup.py build - -if [ $? -ne 0 ]; then - echo >&2 "Error building gdmodule." - exit 1 -fi - -python Setup.py install - -if [ $? -ne 0 ]; then - echo >&2 "Error installing gdmodule." - exit 1 -fi From 5b1c86987d7545568c78ad1fed74ba2ff87e8466 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Thu, 16 Apr 2015 02:58:37 +0000 Subject: [PATCH 289/665] 11111: add doctest: submodule from non-linearly independent generators --- .../finite_dimensional_modules_with_basis.py | 4 ++-- src/sage/categories/modules_with_basis.py | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 9cd6edea429..c86ad8d4701 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -193,13 +193,13 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): By specifying the standard Lie bracket as action, one can compute the commutator of a subspace of `F`:: - sage: F.annihilator_basis([a+b], action = F.bracket) + sage: F.annihilator_basis([a+b], action=F.bracket) [x + y, a, b] In particular one can compute a basis of the center of the algebra. In our example, it is reduced to the identity:: - sage: F.annihilator_basis(F.algebra_generators(), action = F.bracket) + sage: F.annihilator_basis(F.algebra_generators(), action=F.bracket) [x + y] But see also diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index cd94cfc5ff2..3c9793b6f34 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -601,7 +601,7 @@ def submodule(self, gens, - ``gens`` -- a list or family of elements of ``self`` - - ``check`` -- (default: True) whether to verify that the + - ``check`` -- (default: ``True``) whether to verify that the elements of ``gens`` are in ``self``. - ``already_echelonized`` -- (default: ``False``) whether @@ -677,6 +677,20 @@ def submodule(self, gens, ... ValueError: x[0] is not in the image + It is not necessary that the generators of the submodule form + a basis (an explicit basis will be computed):: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]; gens + [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]] + sage: Y = X.submodule(gens, already_echelonized=False) + sage: Y.print_options(prefix='y') + sage: Y + Free module generated by {0, 1} over Rational Field + sage: [b.lift() for b in Y.basis()] + [x[0] - x[2], x[1] - x[2]] + We now implement by hand the center of the algebra of the symmetric group `S_3`:: From 5c6dea208f82cfe3bfc37e9faa7482382c546363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 23:13:33 -0400 Subject: [PATCH 290/665] 11111: proofreading of Franco's proofreading --- src/sage/combinat/free_module.py | 2 +- src/sage/modules/with_basis/subquotient.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 0ee931631aa..84faadc3323 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1590,7 +1590,7 @@ def set_order(self, order): the one used in the generation of the elements of self's associated enumerated set. - .. warning:: Many cached methods depend on this order, in + .. WARNING:: Many cached methods depend on this order, in particular for constructing subspaces and quotients. Changing the order after some computations have been cached does not invalidate the cache, and is likely to diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 12b15410631..86096023a0a 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -76,7 +76,7 @@ def __classcall_private__(cls, submodule, category=None): def __init__(self, submodule, category): r""" - Initialization quotients of a module with basis by a submodule. + Initialize this quotient of a module with basis by a submodule. TESTS:: From 2036314dacabd2816256f07f181a94f0aa37ae32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 15 Apr 2015 23:39:57 -0400 Subject: [PATCH 291/665] 11111: fixed crosslink + missing file in the ref manual --- src/doc/en/reference/modules/index.rst | 1 + .../finite_dimensional_modules_with_basis.py | 4 ++-- src/sage/categories/groups.py | 4 ++-- src/sage/categories/modules.py | 2 +- src/sage/categories/modules_with_basis.py | 14 ++++++++------ 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/doc/en/reference/modules/index.rst b/src/doc/en/reference/modules/index.rst index 9b3ec4bbff9..b94fb10a480 100644 --- a/src/doc/en/reference/modules/index.rst +++ b/src/doc/en/reference/modules/index.rst @@ -30,5 +30,6 @@ Modules sage/modules/with_basis/__init__ sage/modules/with_basis/morphism + sage/modules/with_basis/subquotient .. include:: ../footer.txt diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index c86ad8d4701..c28c3f6be37 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -228,7 +228,7 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate ``self.submodule(submodule)``. - ``check``, ``already_echelonized`` -- passed down to - :meth:`submodule`, which see. + :meth:`ModulesWithBasis.ParentMethods.submodule`. .. WARNING:: @@ -287,7 +287,7 @@ def matrix(self, base_ring=None, side="left"): The order of the rows and columns matches with the order in which the bases are enumerated. - .. SEEALSO:: :func:`_from_matrix` + .. SEEALSO:: :func:`Modules.WithBasis.ParentMethods.module_morphism` EXAMPLES:: diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index f336fa1f223..231fe2a1ad4 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -795,7 +795,7 @@ def central_form(self): - A formal linear combination of the conjugacy class representatives representing its coordinates in the canonical basis of the center. See - :meth:`Groups.Algebras.ParentMethods.center` for + :meth:`Groups.Algebras.ParentMethods.center_basis` for details. .. WARNING:: @@ -830,7 +830,7 @@ def central_form(self): .. SEEALSO:: - - :meth:`Groups.Algebras.ParentMethods.center` + - :meth:`Groups.Algebras.ParentMethods.center_basis` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 72dbdae5215..e8b901d545c 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -178,7 +178,7 @@ def additional_structure(self): .. SEEALSO:: :meth:`Category.additional_structure` - .. TODO:: Should this category be a :class:`CategoryWithAxiom`? + .. TODO:: Should this category be a :class:`~sage.categories.category_with_axiom.CategoryWithAxiom`? EXAMPLES:: diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 3c9793b6f34..8e7ed0ae138 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -247,10 +247,13 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, - ``triangular`` -- (default: ``None``) ``"upper"`` or ``"lower"`` or ``None``: - * ``"upper"`` - if the :meth:`leading_support` of the image - of the basis vector `x_i` is `i`, or - * ``"lower"`` - if the :meth:`trailing_support` of the image - of the basis vector `x_i` is `i`. + * ``"upper"`` - if the + :meth:`~ModulesWithBasis.ElementMethods.leading_support` + of the image of the basis vector `x_i` is `i`, or + + * ``"lower"`` - if the + :meth:`~ModulesWithBasis.ElementMethods.trailing_support` + of the image of the basis vector `x_i` is `i`. - ``unitriangular`` -- (default: ``False``) a boolean. Only meaningful for a triangular morphism. @@ -624,8 +627,7 @@ def submodule(self, gens, .. SEEALSO:: - - :meth:`Modules.WithBasis.ParentMethods.submodule` - - :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` + - :meth:`ModulesWithBasis.FiniteDimensional.ParentMethods.quotient_module` - :class:`sage.modules.with_basis.subquotient.SubmoduleWithBasis` EXAMPLES: From 6a3a07d8ff932196272bf067a1f0d0496ecd8c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 16 Apr 2015 00:00:00 -0400 Subject: [PATCH 292/665] 11111: doc for CombinatorialFreeModule._order_cmp --- src/sage/combinat/free_module.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 84faadc3323..ac47740f417 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1626,7 +1626,7 @@ def get_order(self): def get_order_cmp(self): """ - Returns a comparison function on the basis indices that is + Return a comparison function on the basis indices that is compatible with the current term order. EXAMPLES:: @@ -1644,6 +1644,29 @@ def get_order_cmp(self): return self._order_cmp def _order_cmp(self, x, y): + """ + Compare `x` and `y` w.r.t. the term order. + + INPUT: + + - ``x``, ``y`` -- indices of the basis of ``self`` + + OUTPUT: + + `-1`, `0`, or `1` depending on whether `xy` + w.r.t. the term order. + + EXAMPLES:: + + sage: A = CombinatorialFreeModule(QQ, ['x','y','a','b']) + sage: A.set_order(['x', 'y', 'a', 'b']) + sage: A._order_cmp('x', 'y') + -1 + sage: A._order_cmp('y', 'y') + 0 + sage: A._order_cmp('a', 'y') + 1 + """ return cmp( self._rank_basis(x), self._rank_basis(y) ) From b6d8bff2d4e141b088ebfb7d2aea1b2a7e17dcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 16 Apr 2015 00:23:45 -0400 Subject: [PATCH 293/665] 11111: CombinatorialFreeModule.echelon_from -> Modules.WithBasis.ParentMethods.echelon_form; removed duplicate echelonize; delete meaningless and dangerous argument base_ring --- src/sage/categories/modules_with_basis.py | 40 ++++++++++++++++------- src/sage/combinat/free_module.py | 40 ----------------------- 2 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 8e7ed0ae138..5bb16d01d7c 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -567,33 +567,51 @@ def _repr_(self): name = "Free module generated by {}".format(self.basis().keys()) return name + " over {}".format(self.base_ring()) - def echelonize(self, gens): - """ - A basis in echelon form of the subspace spanned by a finite set of - elements. + def echelon_form(self, elements): + r""" + Return a basis in echelon form of the subspace spanned by + a finite set of elements. INPUT: - - ``gens`` -- a finite set of elements of ``self`` + - ``elements`` -- a list or finite iterable of elements of ``self``. OUTPUT: - A list of elements of ``self`` whose expressions as vectors - is a matrix in echelon form. + 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.echelonize([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V + 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(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']] """ from sage.matrix.constructor import matrix - mat = matrix([g.to_vector() for g in gens]) - return [self.from_vector(v) for v in mat.row_space().basis()] + mat = matrix([g._vector_() for g in elements]) + mat.echelonize() + return [self.from_vector(vec) for vec in mat if vec] def submodule(self, gens, check=True, already_echelonized=False, category=None): @@ -728,7 +746,7 @@ def submodule(self, gens, sage: TestSuite(center).run() """ if not already_echelonized: - gens = self.echelonize(gens) + gens = self.echelon_form(gens) from sage.modules.with_basis.subquotient import SubmoduleWithBasis return SubmoduleWithBasis(gens, ambient=self, category=category) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index ac47740f417..7de5ed3c608 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -2084,46 +2084,6 @@ def _from_dict( self, d, coerce=False, remove_zeros=True ): d = dict( (key, coeff) for key, coeff in d.iteritems() if coeff) return self.element_class( self, d ) - def echelon_form(self, elements, base_ring=None): - r""" - Compute the echelon form of the given elements. - - INPUT: - - - ``elements`` - a list of elements of ``self``. - - - ``base_ring`` - ring (default: ``None``): compute the echelon - form over the given ring; if ``base_ring`` is ``None``, then uses - the base ring of ``self``. - - OUTPUT: - - - list of elements of ``self`` - - EXAMPLES:: - - 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.echelon_form(elements, base_ring=QQ) - [B[1] - 17*B[2] + B[4], B[3] - 1/6*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']] - """ - from sage.matrix.constructor import matrix - if base_ring is None: - base_ring = self.base_ring() - mat = matrix(base_ring, map(vector,elements)) - mat.echelonize() - return [self.from_vector(vec) for vec in mat if vec != 0] - class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules From 25881cc50c7e44b581aba8e7ac67cada770eb7a7 Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Thu, 16 Apr 2015 05:03:20 +0000 Subject: [PATCH 294/665] 11111: docstring improvement for quotient_module --- .../categories/finite_dimensional_modules_with_basis.py | 6 +++--- src/sage/categories/semisimple_algebras.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index c28c3f6be37..b6e437801d0 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -219,7 +219,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): r""" - Construct the quotient free module ``self``/``submodule`` + Construct a free quotient module ``self``/``submodule``. INPUT: @@ -233,8 +233,8 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate .. WARNING:: At this point, only quotients by free submodules whose - basis can be put in unitriangular echelon form are - supported. + basis admits a unitriangular echelon form are supported + (so that the quotient is also a free module). EXAMPLES:: diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 5539ac72dfb..323febe2f93 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -83,8 +83,6 @@ def super_categories(self): R = self.base_ring() return [Algebras(R)] - # TODO: trivial implementations for semisimple_quotient - class ParentMethods: def radical_basis(self, **keywords): From 41f0a571ed77dd4e9a5d8ca9fdfe8837799ff6e9 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Thu, 16 Apr 2015 08:32:07 +0200 Subject: [PATCH 295/665] fix broken docstring --- src/sage/symbolic/expression.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 82281df596d..5d94c6f6225 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -10307,7 +10307,7 @@ cdef class Expression(CommutativeRingElement): return fast_callable(self, etb) def show(self): - """ + r""" Pretty-Print this symbolic expression This typeset it nicely and prints it immediately. From 4301c4cbdb48a00e9950292b7ce2e84a2b0388c0 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 16 Apr 2015 08:47:47 +0200 Subject: [PATCH 296/665] trac #17927: n=None and k!=None not supported --- src/sage/combinat/integer_vector.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 84dfc3a603e..8a1a53fec9b 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -638,8 +638,14 @@ def IntegerVectors(n=None, k=None, **kwargs): Traceback (most recent call last): ... TypeError: __init__() got an unexpected keyword argument 'length' + sage: IntegerVectors(None, 4) + Traceback (most recent call last): + ... + NotImplementedError: k must be None when n is None """ if n is None: + if k is not None: + raise NotImplementedError("k must be None when n is None") return IntegerVectors_all(**kwargs) elif k is None: return IntegerVectors_nconstraints(n, kwargs) From ad147af99d95b30dec160dd649f1998697247f73 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 11 Mar 2015 14:25:30 +0100 Subject: [PATCH 297/665] Ref: add missing modules to r/misc, r/structure Minimally sphinxify or fix their docstrings so that the reference manual still builds, but not necessarily so that they are correctly formatted. Tables of contents to be sorted later. --- src/doc/en/reference/misc/index.rst | 69 +++++- src/doc/en/reference/structure/index.rst | 16 ++ src/sage/databases/sql_db.py | 134 +++++------ src/sage/ext/fast_callable.pyx | 233 +++++++++++--------- src/sage/interfaces/frobby.py | 4 +- src/sage/media/channels.pyx | 2 + src/sage/media/wav.py | 43 ++-- src/sage/misc/abstract_method.py | 2 +- src/sage/misc/banner.py | 41 ++-- src/sage/misc/benchmark.py | 32 ++- src/sage/misc/citation.pyx | 2 + src/sage/misc/copying.py | 2 + src/sage/misc/cython_c.pyx | 2 + src/sage/misc/derivative.pyx | 59 ++--- src/sage/misc/flatten.py | 27 ++- src/sage/misc/fpickle.pyx | 15 +- src/sage/misc/lazy_attribute.pyx | 2 +- src/sage/misc/map_threaded.py | 9 +- src/sage/misc/multireplace.py | 2 + src/sage/misc/parser.pyx | 127 +++++++---- src/sage/misc/python.py | 17 +- src/sage/misc/remote_file.py | 2 + src/sage/misc/reset.pyx | 2 + src/sage/misc/sh.py | 6 +- src/sage/misc/superseded.py | 4 +- src/sage/structure/coerce_exceptions.py | 2 + src/sage/structure/factorization_integer.py | 2 + src/sage/structure/generators.pyx | 4 +- src/sage/structure/misc.pyx | 25 ++- src/sage/structure/nonexact.py | 4 +- src/sage/structure/proof/proof.py | 30 ++- src/sage_setup/autogen/interpreters.py | 27 ++- 32 files changed, 592 insertions(+), 356 deletions(-) diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 17f94f7cdc3..711ec63bcbc 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -12,7 +12,6 @@ Miscellaneous sage/misc/c3 sage/misc/c3_controlled sage/misc/decorators - sage/misc/lazy_list sage/misc/classgraph sage/misc/dev_tools sage/misc/function_mangling @@ -51,8 +50,43 @@ Miscellaneous sage/misc/viewer sage/misc/session sage/misc/defaults - sage/misc/superseded + sage/ext/multi_modular + sage/ext/memory + + sage/media/channels + sage/media/wav + + sage/misc/banner + sage/misc/benchmark + sage/misc/binary_tree + sage/misc/cache + sage/misc/citation + sage/misc/copying + sage/misc/cython_c + sage/misc/flatten + + sage/misc/fpickle + sage/misc/inline_fortran + sage/misc/map_threaded + sage/misc/mathml + sage/misc/memory_info + sage/misc/method_decorator + sage/misc/misc_c + sage/misc/multireplace + sage/misc/object_multiplexer + sage/misc/pager + sage/misc/parser + sage/misc/prandom + sage/misc/python + sage/misc/remote_file + sage/misc/reset + sage/misc/sage_itertools + sage/misc/sage_ostools + sage/misc/search + sage/misc/sh + sage/misc/stopgap + sage/misc/superseded Profiling and Performance Testing --------------------------------- @@ -85,5 +119,36 @@ Lazyness sage/misc/lazy_attribute sage/misc/lazy_format sage/misc/lazy_import + sage/misc/lazy_list + sage/misc/lazy_import_cache + sage/misc/lazy_string + +Fast Expression Evaluation +-------------------------- + +.. toctree:: + :maxdepth: 2 + + sage/ext/fast_callable + sage/ext/fast_eval + +.. The docbuilder only accepts modules from src/sage/* in the reference +.. manual (#18216) +.. sage_setup/autogen/interpreters + +.. Automatically generated interpreters, probably shouldn't be documented. +.. sage/ext/interpreters/wrapper_cdf +.. sage/ext/interpreters/wrapper_el +.. sage/ext/interpreters/wrapper_py +.. sage/ext/interpreters/wrapper_rdf +.. sage/ext/interpreters/wrapper_rr + +Databases +--------- + +.. toctree:: + :maxdepth: 2 + + sage/databases/sql_db .. include:: ../footer.txt diff --git a/src/doc/en/reference/structure/index.rst b/src/doc/en/reference/structure/index.rst index f7149a821eb..d56c36092e6 100644 --- a/src/doc/en/reference/structure/index.rst +++ b/src/doc/en/reference/structure/index.rst @@ -12,6 +12,7 @@ Basic Structures sage/structure/coerce_dict sage/structure/formal_sum sage/structure/factorization + sage/structure/factorization_integer sage/structure/element sage/structure/unique_representation sage/structure/factory @@ -43,5 +44,20 @@ Basic Structures sage/structure/parent + sage/structure/proof/proof + sage/misc/proof + + sage/structure/coerce_exceptions + sage/structure/debug_options + sage/structure/element_verify + sage/structure/generators + sage/structure/gens_py + sage/structure/graphics_file + sage/structure/list_clone_timings + sage/structure/list_clone_timings_cy + sage/structure/misc + sage/structure/nonexact + sage/structure/test_factory + .. include:: ../footer.txt diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 36da1ac8c41..f862d9a4e9b 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -8,22 +8,18 @@ that wrap the basic functionality of sqlite. Databases are constructed via a triple indexed dictionary called a - skeleton. A skeleton should be constructed to fit the following format: - - - skeleton -- a triple-indexed dictionary - - - outer key -- table name - - - inner key -- column name - - - inner inner key -- one of the following: - - - primary_key -- boolean, whether column has been set as - primary key - - index -- boolean, whether column has been set as index - - unique -- boolean, whether column has been set as unique - - sql -- one of 'TEXT', 'BOOLEAN', 'INTEGER', 'REAL', or - other user defined type + skeleton. A skeleton should be constructed to fit the following format:: + + | - skeleton -- a triple-indexed dictionary + | - outer key -- table name + | - inner key -- column name + | - inner inner key -- one of the following: + | - ``primary_key`` -- boolean, whether column has been set as + primary key + | - ``index`` -- boolean, whether column has been set as index + | - ``unique`` -- boolean, whether column has been set as unique + | - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, ``'INTEGER'``, + ``'REAL'``, or other user defined type An example skeleton of a database with one table, that table with one column:: @@ -48,16 +44,15 @@ interface. AUTHORS: - -- R. Andrew Ohana (2011-07-16): refactored and rewrote most of the code; - merged the Generic classes into the - non-Generic versions; changed the - skeleton format to include a boolean - indicating whether the column stores - unique keys; changed the index names so - as to avoid potential ambiguity - -- Emily A. Kirkman (2008-09-20): added functionality to generate plots and - reformat output in show - -- Emily A. Kirkman and Robert L. Miller (2007-06-17): initial version + +- R. Andrew Ohana (2011-07-16): refactored and rewrote most of the code; + merged the Generic classes into the non-Generic versions; changed the + skeleton format to include a boolean indicating whether the column stores + unique keys; changed the index names so as to avoid potential ambiguity +- Emily A. Kirkman (2008-09-20): added functionality to generate plots and + reformat output in show +- Emily A. Kirkman and Robert L. Miller (2007-06-17): initial version + """ # FUTURE TODOs (Ignore for now): # - order by clause in query strings @@ -217,24 +212,18 @@ def verify_operator(operator): def construct_skeleton(database): """ Constructs a database skeleton from the sql data. The skeleton data - structure is a triple indexed dictionary of the following format: - - - skeleton -- a triple-indexed dictionary - - - outer key -- table name - - - inner key -- column name - - - inner inner key -- one of the following: - - - ``primary_key`` -- boolean, whether column has been set - as primary key - - ``index`` -- boolean, whether column has been set as - index - - ``unique`` -- boolean, whether column has been set as - unique - - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, - ``'INTEGER'``, ``'REAL'``, or other user defined type + structure is a triple indexed dictionary of the following format:: + + | - skeleton -- a triple-indexed dictionary + | - outer key -- table name + | - inner key -- column name + | - inner inner key -- one of the following: + | - ``primary_key`` -- boolean, whether column has been set as + primary key + | - ``index`` -- boolean, whether column has been set as index + | - ``unique`` -- boolean, whether column has been set as unique + | - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, ``'INTEGER'``, + ``'REAL'``, or other user defined type An example skeleton of a database with one table, that table with one column:: @@ -879,22 +868,19 @@ def __init__(self, filename=None, read_only=None, skeleton=None): INPUT: - ``filename`` -- a string - - ``skeleton`` -- a triple-indexed dictionary + - ``skeleton`` -- a triple-indexed dictionary:: - - outer key -- table name - - - inner key -- column name - - - inner inner key -- one of the following: - - - ``primary_key`` -- boolean, whether column has been - set as primary key - - ``index`` -- boolean, whether column has been set as - index - - ``unique`` -- boolean, whether column has been set as - unique - - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, - ``'INTEGER'``, ``'REAL'``, or other user defined type + | - outer key -- table name + | - inner key -- column name + | - inner inner key -- one of the following: + | - ``primary_key`` -- boolean, whether column has been set + as primary key + | - ``index`` -- boolean, whether column has been set as + index + | - ``unique`` -- boolean, whether column has been set as + unique + | - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, + ``'INTEGER'``, ``'REAL'``, or other user defined type TUTORIAL: @@ -1186,24 +1172,18 @@ def save(self, filename): def get_skeleton(self, check=False): """ Returns a dictionary representing the hierarchical structure of the - database, in the following format. - - - skeleton -- a triple-indexed dictionary - - - outer key -- table name - - - inner key -- column name - - - inner inner key -- one of the following: - - - ``primary_key`` -- boolean, whether column has been - set as primary key - - ``index`` -- boolean, whether column has been set as - index - - ``unique`` -- boolean, whether column has been set as - unique - - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, - ``'INTEGER'``, ``'REAL'``, or other user defined type + database, in the following format:: + + | - skeleton -- a triple-indexed dictionary + | - outer key -- table name + | - inner key -- column name + | - inner inner key -- one of the following: + | - ``primary_key`` -- boolean, whether column has been set as + primary key + | - ``index`` -- boolean, whether column has been set as index + | - ``unique`` -- boolean, whether column has been set as unique + | - ``sql`` -- one of ``'TEXT'``, ``'BOOLEAN'``, ``'INTEGER'``, + ``'REAL'``, or other user defined type For example:: diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index bde710f9d40..d6e2410a15d 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -11,7 +11,7 @@ via recursive calls over a python representation of the object (even if Maxima or other outside packages are not involved) is extremely inefficient. -This module provides a function, \function{fast_callable}, to +This module provides a function, :func:`fast_callable`, to transform such expressions into a form where they can be evaluated quickly:: @@ -22,9 +22,9 @@ quickly:: sage: ff(RIF(3.5)) 36.39921677231038? -By default, \function{fast_callable} only removes some interpretive +By default, :func:`fast_callable` only removes some interpretive overhead from the evaluation, but all of the individual arithmetic -operations are done using standard \sage arithmetic. This is still a +operations are done using standard Sage arithmetic. This is still a huge win over sage.calculus, which evidently has a lot of overhead. Compare the cost of evaluating Wilkinson's polynomial (in unexpanded form) at x=30:: @@ -38,7 +38,7 @@ form) at x=30:: 625 loops, best of 3: 9.72 us per loop You can specify a particular domain for the evaluation using -\code{domain=}:: +``domain=``:: sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ) @@ -94,7 +94,7 @@ And support for ``CDF``:: sage: timeit('fc_wilk_rr(30.0)') # random, long time 625 loops, best of 3: 10.2 us per loop -Currently, \function{fast_callable} can accept two kinds of objects: +Currently, :func:`fast_callable` can accept two kinds of objects: polynomials (univariate and multivariate) and symbolic expressions (elements of the Symbolic Ring). (This list is likely to grow significantly in the near future.) For polynomials, you can omit the @@ -113,7 +113,7 @@ ordering (you can include extra variable names here, too). :: sage: fp = fast_callable(p, vars=('x','w','z','y')) For symbolic expressions, you need to specify the variable names, so -that \function{fast_callable} knows what order to use. :: +that :func:`fast_callable` knows what order to use. :: sage: var('y,z,x') (y, z, x) @@ -128,28 +128,28 @@ You can also specify extra variable names:: sage: ff(1,2,3,4) 341 -This should be enough for normal use of \function{fast_callable}; let's +This should be enough for normal use of :func:`fast_callable`; let's discuss some more advanced topics. Sometimes it may be useful to create a fast version of an expression without going through symbolic expressions or polynomials; perhaps -because you want to describe to \function{fast_callable} an expression +because you want to describe to :func:`fast_callable` an expression with common subexpressions. -Internally, \function{fast_callable} works in two stages: it constructs +Internally, :func:`fast_callable` works in two stages: it constructs an expression tree from its argument, and then it builds a fast evaluator from that expression tree. You can bypass the first phase by building your own expression tree and passing that directly to -\function{fast_callable}, using an \class{ExpressionTreeBuilder}. :: +:func:`fast_callable`, using an :class:`ExpressionTreeBuilder`. :: sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=('x','y','z')) -An \class{ExpressionTreeBuilder} has three interesting methods: -\method{constant}, \method{var}, and \method{call}. -All of these methods return \class{ExpressionTree} objects. +An :class:`ExpressionTreeBuilder` has three interesting methods: +:meth:`constant`, :meth:`var`, and :meth:`call`. +All of these methods return :class:`ExpressionTree` objects. -The \method{var} method takes a string, and returns an expression tree +The :meth:`var` method takes a string, and returns an expression tree for the corresponding variable. :: sage: x = etb.var('x') @@ -161,12 +161,12 @@ build expression trees representing arithmetic expressions. :: sage: v1 = (x+y)*(y+z) + (y//z) -The \method{constant} method takes a \sage value, and returns an +The :meth:`constant` method takes a Sage value, and returns an expression tree representing that value. :: sage: v2 = etb.constant(3.14159) * x + etb.constant(1729) * y -The \method{call} method takes a \sage/Python function and zero or more +The :meth:`call` method takes a sage/Python function and zero or more expression trees, and returns an expression tree representing the function call. :: @@ -174,9 +174,9 @@ the function call. :: sage: v3 sin(add(add(mul(add(v_0, v_1), add(v_1, v_1)), floordiv(v_1, v_1)), add(mul(3.14159000000000, v_0), mul(1729, v_1)))) -Many \sage/Python built-in functions are specially handled; for instance, -when evaluating an expression involving \function{sin} over \code{RDF}, -the C math library function \function{sin} is called. Arbitrary functions +Many sage/Python built-in functions are specially handled; for instance, +when evaluating an expression involving :func:`sin` over ``RDF``, +the C math library function :func:`sin` is called. Arbitrary functions are allowed, but will be much slower since they will call back to Python code on every call; for example, the following will work. :: @@ -186,10 +186,10 @@ Python code on every call; for example, the following will work. :: sage: fast_callable(e)(1, 2, 3) 3.60555127546399 -To provide \function{fast_callable} for your own class (so that -\code{fast_callable(x)} works when \variable{x} is an instance of your -class), implement a method \code{_fast_callable_(self, etb)} for your class. -This method takes an \class{ExpressionTreeBuilder}, and returns an +To provide :func:`fast_callable` for your own class (so that +``fast_callable(x)`` works when ``x`` is an instance of your +class), implement a method ``_fast_callable_(self, etb)`` for your class. +This method takes an :class:`ExpressionTreeBuilder`, and returns an expression tree built up using the methods described above. EXAMPLES:: @@ -198,15 +198,17 @@ EXAMPLES:: x sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float) +:: + sage: f(1) 1.4142135623730951 sage: f.op_list() [('load_arg', 0), ('ipow', 7), ('load_const', 1.0), 'add', 'sqrt', 'return'] - To interpret that last line, we load argument 0 ('x' in this case) onto - the stack, push the constant 7.0 onto the stack, call the pow function - (which takes 2 arguments from the stack), push the constant 1.0, add the - top two arguments of the stack, and then call sqrt. +To interpret that last line, we load argument 0 ('x' in this case) onto +the stack, push the constant 7.0 onto the stack, call the pow function +(which takes 2 arguments from the stack), push the constant 1.0, add the +top two arguments of the stack, and then call sqrt. Here we take sin of the first argument and add it to f:: @@ -220,8 +222,58 @@ Here we take sin of the first argument and add it to f:: AUTHOR: - -- Carl Witty (2009-02): initial version (heavily inspired by - Robert Bradshaw's fast_eval.pyx) + +- Carl Witty (2009-02): initial version (heavily inspired by + Robert Bradshaw's fast_eval.pyx) + +.. TODO:: + + The following bits of text were written for the module docstring. + They are not true yet, but I hope they will be true someday, at + which point I will move them into the main text. + + The final interesting method of :class:`ExpressionTreeBuilder` is + :meth:`choice`. This produces conditional expressions, like the C + ``COND ? T : F`` expression or the Python ``T if COND else F``. + This lets you define piecewise functions using :func:`fast_callable`. :: + + sage: v4 = etb.choice(v3 >= etb.constant(0), v1, v2) + + The arguments are ``(COND, T, F)`` (the same order as in C), so the + above means that if ``v3`` evaluates to a nonnegative number, + then ``v4`` will evaluate to the result of ``v1``; + otherwise, ``v4`` will evaluate to the result of ``v2``. + + Let's see an example where we see that :func:`fast_callable` does not + evaluate common subexpressions more than once. We'll make a + :func:`fast_callable` expression that gives the result + of 16 iterations of the Mandelbrot function. :: + + sage: etb = ExpressionTreeBuilder('c') + sage: z = etb.constant(0) + sage: c = etb.var('c') + sage: for i in range(16): + ... z = z*z + c + sage: mand = fast_callable(z, domain=CDF) # not tested + + Now ``ff`` does 32 complex arithmetic operations on each call + (16 additions and 16 multiplications). However, if ``z*z`` produced + code that evaluated ``z`` twice, then this would do many + thousands of arithmetic operations instead. + + Note that the handling for common subexpressions only checks whether + expression trees are the same Python object; for instance, the following + code will evaluate ``x+1`` twice:: + + sage: etb = ExpressionTreeBuilder('x') + sage: x = etb.var('x') + sage: (x+1)*(x+1) # not tested + *(+(v_0, 1), +(v_0, 1)) + + but this code will only evaluate ``x+1`` once:: + + sage: v = x+1; v*v # not tested + *(+(v_0, 1), +(v_0, 1)) """ @@ -241,53 +293,6 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -# The following bits of text were written for the module docstring. -# They are not true yet, but I hope they will be true someday, at -# which point I will move them into the docstring. -#------------------------------ WRONG (for now) docs follow -# The final interesting method of \class{ExpressionTreeBuilder} is -# \method{choice}. This produces conditional expressions, like the C -# \code{COND ? T : F} expression or the Python {T if COND else F}. -# This lets you define piecewise functions using \function{fast_callable}. - -# sage: v4 = etb.choice(v3 >= etb.constant(0), v1, v2) - -# The arguments are \code{(COND, T, F)} (the same order as in C), so the -# above means that if \variable{v3} evaluates to a nonnegative number, -# then \variable{v4} will evaluate to the result of \variable{v1}; -# otherwise, \variable{v4} will evaluate to the result of \variable{v2}. - -# Let's see an example where we see that \function{fast_callable} does not -# evaluate common subexpressions more than once. We'll make a -# \function{fast_callable} expression that gives the result -# of 16 iterations of the Mandelbrot function. - -# sage: etb = ExpressionTreeBuilder('c') -# sage: z = etb.constant(0) -# sage: c = etb.var('c') -# sage: for i in range(16): -# ... z = z*z + c -# sage: mand = fast_callable(z, domain=CDF) # not tested - -# Now \variable{ff} does 32 complex arithmetic operations on each call -# (16 additions and 16 multiplications). However, if \code{z*z} produced -# code that evaluated \variable{z} twice, then this would do many -# thousands of arithmetic operations instead. - -# Note that the handling for common subexpressions only checks whether -# expression trees are the same Python object; for instance, the following -# code will evaluate \code{x+1} twice: - -# sage: etb = ExpressionTreeBuilder('x') -# sage: x = etb.var('x') -# sage: (x+1)*(x+1) -# *(+(v_0, 1), +(v_0, 1)) - -# but this code will only evaluate \code{x+1} once: - -# sage: v = x+1; v*v -# *(+(v_0, 1), +(v_0, 1)) -#------------------------------ done with WRONG (for now) docs import operator @@ -339,7 +344,7 @@ def fast_callable(x, domain=None, vars=None, (Actually it's the same interpreter; only the return type varies.) Note that the float interpreter is not actually more accurate than the RDF interpreter; elements of RDF just don't display all - their digits. We have special fast interpreter for domain=CDF. + their digits. We have special fast interpreter for domain=CDF:: sage: f_float = fast_callable(expr, vars=[x], domain=float) sage: f_float(2) @@ -376,6 +381,8 @@ def fast_callable(x, domain=None, vars=None, sage: n(symbolic_result) -98.0015640336293 + :: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=('x','y'), domain=float) sage: x = etb.var('x') @@ -387,7 +394,7 @@ def fast_callable(x, domain=None, vars=None, 0.5514266812416906 Check that fast_callable also works for symbolic functions with evaluation - functions: + functions:: sage: def evalf_func(self, x, y, parent): return parent(x*y) if parent != None else x*y sage: x,y = var('x,y') @@ -396,7 +403,7 @@ def fast_callable(x, domain=None, vars=None, sage: fc(3, 4) f(3, 4) - And also when there are complex values involved: + And also when there are complex values involved:: sage: def evalf_func(self, x, y, parent): return parent(I*x*y) if parent != None else I*x*y sage: g = function('g', evalf_func=evalf_func) @@ -1353,7 +1360,8 @@ cdef class ExpressionChoice(Expression): (It's possible to create choice nodes, but they don't work yet.) - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: etb.choice(etb.call(operator.eq, x, 0), 0, 1/x) @@ -1460,7 +1468,8 @@ cpdef _expression_binop_helper(s, o, op): Makes an Expression for (s op o). Either s or o (or both) must already be an expression. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import _expression_binop_helper, ExpressionTreeBuilder sage: var('x,y') (x, y) @@ -1468,13 +1477,15 @@ cpdef _expression_binop_helper(s, o, op): sage: x = etb(x) Now x is an Expression, but y is not. Still, all the following - cases work. + cases work:: + sage: _expression_binop_helper(x, x, operator.add) add(v_0, v_0) sage: _expression_binop_helper(x, y, operator.add) add(v_0, v_1) sage: _expression_binop_helper(y, x, operator.add) add(v_1, v_0) + """ # The Cython way of handling operator overloading on cdef classes # (which is inherited from Python) is quite annoying. Inside the @@ -1509,7 +1520,8 @@ class IntegerPowerFunction(object): power n. That is, IntegerPowerFunction(2) is the squaring function; IntegerPowerFunction(-1) is the reciprocal function. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import IntegerPowerFunction sage: square = IntegerPowerFunction(2) sage: square @@ -1596,7 +1608,8 @@ cpdef dict get_builtin_functions(): We delay building builtin_functions to break a circular import between sage.calculus and this file. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import get_builtin_functions sage: builtins = get_builtin_functions() sage: sorted(list(builtins.values())) @@ -1649,7 +1662,8 @@ cpdef generate_code(Expression expr, InstructionStream stream): by walking the Expression and sending the corresponding stack instructions to an InstructionStream. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder, generate_code, InstructionStream sage: etb = ExpressionTreeBuilder('x') sage: x = etb.var('x') @@ -1664,7 +1678,8 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: v(7) 8*pi + 56 - TESTS: + TESTS:: + sage: def my_sin(x): return sin(x) sage: def my_norm(x, y): return x*x + y*y sage: def my_sqrt(x): @@ -1755,6 +1770,8 @@ cpdef generate_code(Expression expr, InstructionStream stream): ... TypeError: unable to convert sin(3) to an integer + :: + sage: fc = fast_callable(etb(x)^100) sage: fc(pi) pi^100 @@ -1799,7 +1816,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: base^expo 1.00000095367477 - Make sure we don't overflow the stack with highly nested expressions (#11766): + Make sure we don't overflow the stack with highly nested expressions (#11766):: sage: R. = CC[] sage: f = R(range(100000)) @@ -1905,11 +1922,14 @@ cdef class InstructionStream: Initialize an InstructionStream. INPUTS: - metadata - The metadata_by_opname from a wrapper module - n_args - The number of arguments accessible by the generated code - (this is just passed to the wrapper class) - domain - The domain of interpretation (this is just passed to the - wrapper class) + + - metadata - The metadata_by_opname from a wrapper module + + - n_args - The number of arguments accessible by the generated code + (this is just passed to the wrapper class) + + - domain - The domain of interpretation (this is just passed to the + wrapper class) EXAMPLES:: @@ -1961,7 +1981,8 @@ cdef class InstructionStream: [('load_const', 5), ('load_const', 7), ('load_const', 5)] Note that constants are shared: even though we load 5 twice, it - only appears once in the constant table. + only appears once in the constant table. :: + sage: instr_stream.get_current()['constants'] [5, 7] """ @@ -2216,17 +2237,18 @@ class CompilerInstrSpec(object): The parameter list is a list of strings. Each string is one of the following: - - 'args' - The instruction argument refers to an input argument - of the wrapper class; it is just appended to the code. - - 'constants', 'py_constants' - The instruction argument is a value; - the value is added to the corresponding list (if it's - not already there) and the index is appended to the - code. - - 'n_inputs', 'n_outputs' - The instruction actually takes a variable - number of inputs or outputs (the n_inputs and n_outputs - attributes of this instruction are ignored). - The instruction argument specifies the number of inputs - or outputs (respectively); it is just appended to the code. + - 'args' - The instruction argument refers to an input argument of the + wrapper class; it is just appended to the code. + + - 'constants', 'py_constants' - The instruction argument is a value; the + value is added to the corresponding list (if it's not already there) and + the index is appended to the code. + + - 'n_inputs', 'n_outputs' - The instruction actually takes a variable + number of inputs or outputs (the n_inputs and n_outputs attributes of + this instruction are ignored). The instruction argument specifies the + number of inputs or outputs (respectively); it is just appended to the + code. """ def __init__(self, n_inputs, n_outputs, parameters): @@ -2276,7 +2298,8 @@ def op_list(args, metadata): have a wrapper object, call op_list on it; if you have an InstructionStream object, call current_op_list on it. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.interpreters.wrapper_rdf import metadata sage: from sage.ext.fast_callable import InstructionStream, op_list sage: instr_stream = InstructionStream(metadata, 1) diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 8625b881d4b..1eb3a8a7345 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -12,8 +12,8 @@ AUTHORS: -Bjarke Hammersholt Roune (2008-04-25): Wrote the Frobby C++ -program and the initial version of the Python interface. +- Bjarke Hammersholt Roune (2008-04-25): Wrote the Frobby C++ + program and the initial version of the Python interface. NOTES: diff --git a/src/sage/media/channels.pyx b/src/sage/media/channels.pyx index 79f991184c9..b605a6a73de 100644 --- a/src/sage/media/channels.pyx +++ b/src/sage/media/channels.pyx @@ -1,3 +1,5 @@ +"_separate_channels" + def _separate_channels(_data, _width, _nchannels): """ Separates the channels. This is an internal helper method for diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index cd41b286f60..89e437dcb94 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -19,9 +19,10 @@ sample, and the number of channels in the file. AUTHORS: - -- Bobby Moretti and Gonzolo Tornaria (2007-07-01): First version - -- William Stein (2007-07-03): add more - -- Bobby Moretti (2007-07-03): add doctests + +- Bobby Moretti and Gonzolo Tornaria (2007-07-01): First version +- William Stein (2007-07-03): add more +- Bobby Moretti (2007-07-03): add doctests """ import math @@ -39,23 +40,25 @@ class Wave(SageObject): A class wrapping a wave audio file. INPUT: - You must call Wave() with either data = filename, where - filename is the name of a wave file, or with each of the - following options: - - channels -- the number of channels in the wave file (1 for - mono, 2 for stereo, etc... - width -- the number of bytes per sample - framerate -- the number of frames per second - nframes -- the number of frames in the data stream - bytes -- a string object containing the bytes of the - data stream + + You must call Wave() with either data = filename, where + filename is the name of a wave file, or with each of the + following options: + + - channels -- the number of channels in the wave file (1 for mono, 2 for + stereo, etc... + - width -- the number of bytes per sample + - framerate -- the number of frames per second + - nframes -- the number of frames in the data stream + - bytes -- a string object containing the bytes of the data stream Slicing: + Slicing a Wave object returns a new wave object that has been trimmed to the bytes that you have given it. Indexing: + Getting the $n$th item in a Wave object will give you the value of the $n$th frame. """ @@ -267,13 +270,15 @@ def plot(self, npoints=None, channel=0, plotjoined=True, **kwds): Plots the audio data. INPUT: - npoints -- number of sample points to take; if not given, draws - all known points. - channel -- 0 or 1 (if stereo). default: 0 - plotjoined -- whether to just draw dots or draw lines between sample points + + - npoints -- number of sample points to take; if not given, draws all + known points. + - channel -- 0 or 1 (if stereo). default: 0 + - plotjoined -- whether to just draw dots or draw lines between sample points OUTPUT: - a plot object that can be shown. + + a plot object that can be shown. """ domain = self.domain(npoints = npoints) diff --git a/src/sage/misc/abstract_method.py b/src/sage/misc/abstract_method.py index 80b78c678b7..f5e5b242331 100644 --- a/src/sage/misc/abstract_method.py +++ b/src/sage/misc/abstract_method.py @@ -192,7 +192,7 @@ def _sage_src_lines_(self): sage: src[0] 'def banner():\n' sage: lines - 78 + 82 """ from sage.misc.sageinspect import sage_getsourcelines return sage_getsourcelines(self._f) diff --git a/src/sage/misc/banner.py b/src/sage/misc/banner.py index 361ed1e796f..20c44480ad9 100644 --- a/src/sage/misc/banner.py +++ b/src/sage/misc/banner.py @@ -19,11 +19,15 @@ def version(clone = False): Return the version of Sage. INPUT: - nothing + + nothing + OUTPUT: - str - EXAMPLES: + str + + EXAMPLES:: + sage: version() 'SageMath Version ..., Release Date: ...' sage: version(clone=True) @@ -104,18 +108,23 @@ def version_dict(): A dictionary describing the version of Sage. INPUT: - nothing + + nothing + OUTPUT: - dictionary with keys 'major', 'minor', 'tiny', 'prerelease' + + dictionary with keys 'major', 'minor', 'tiny', 'prerelease' This process the Sage version string and produces a dictionary. - It expects the Sage version to be in one of these forms: + It expects the Sage version to be in one of these forms:: + N.N N.N.N N.N.N.N N.N.str N.N.N.str N.N.N.N.str + where 'N' stands for an integer and 'str' stands for a string. The first integer is stored under the 'major' key and the second integer under 'minor'. If there is one more integer, it is stored @@ -130,7 +139,8 @@ def version_dict(): If the Sage version is '3.2.alpha0', then the dictionary is {'major': 3, 'minor': 2, 'tiny': 0, 'prerelease': True}. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.banner import version_dict sage: print "SageMath major version is %s" % version_dict()['major'] SageMath major version is ... @@ -162,14 +172,16 @@ def require_version(major, minor=0, tiny=0, prerelease=False, True if Sage version is at least major.minor.tiny. INPUT: - major -- integer - minor -- integer (optional, default = 0) - tiny -- float (optional, default = 0) - prerelease -- boolean (optional, default = False) - print_message -- boolean (optional, default = False) + + - major -- integer + - minor -- integer (optional, default = 0) + - tiny -- float (optional, default = 0) + - prerelease -- boolean (optional, default = False) + - print_message -- boolean (optional, default = False) OUTPUT: - True if major.minor.tiny is <= version of Sage, False otherwise + + True if major.minor.tiny is <= version of Sage, False otherwise For example, if the Sage version number is 3.1.2, then require_version(3, 1, 3) will return False, while @@ -184,7 +196,8 @@ def require_version(major, minor=0, tiny=0, prerelease=False, If optional argument print_message is True and this function is returning False, print a warning message. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.banner import require_version sage: require_version(2, 1, 3) True diff --git a/src/sage/misc/benchmark.py b/src/sage/misc/benchmark.py index 14588395e86..cd91008ca14 100644 --- a/src/sage/misc/benchmark.py +++ b/src/sage/misc/benchmark.py @@ -1,3 +1,5 @@ +"Benchmarks" + from misc import cputime from sage.all import * @@ -8,13 +10,17 @@ def benchmark(n=-1): takes for each to run. INPUT: + n -- int (default: -1) the benchmark number; the default of -1 runs all the benchmarks. + OUTPUT: + list -- summary of timings for each benchmark. int -- if n == -1, also return the total time - EXAMPLE: + EXAMPLE:: + sage: from sage.misc.benchmark import * sage: _ = benchmark() Running benchmark 0 @@ -76,7 +82,8 @@ def bench0(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench0()[0] Benchmark 0: Factor the following polynomial over @@ -95,7 +102,8 @@ def bench1(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench1()[0] Find the Mordell-Weil group of the elliptic curve 5077A using mwrank @@ -111,7 +119,8 @@ def bench2(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench2()[0] Some basic arithmetic with very large Integer numbers: '3^1000001 * 19^100001 @@ -126,7 +135,8 @@ def bench3(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench3()[0] Some basic arithmetic with very large Rational numbers: '(2/3)^100001 * (17/19)^100001 @@ -141,7 +151,8 @@ def bench4(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench4()[0] Rational polynomial arithmetic using Sage. Compute (x^29+17*x-5)^200. @@ -158,7 +169,8 @@ def bench5(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench5()[0] Rational polynomial arithmetic using Sage. Compute (x^19 - 18*x + 1)^50 one hundred times. @@ -175,7 +187,8 @@ def bench6(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench6()[0] Compute the p-division polynomials of y^2 = x^3 + 37*x - 997 for primes p < 40. @@ -192,7 +205,8 @@ def bench7(): """ Run a benchmark. - BENCHMARK: + BENCHMARK:: + sage: from sage.misc.benchmark import * sage: print bench7()[0] Compute the Mordell-Weil group of y^2 = x^3 + 37*x - 997. diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index 13770b9e91d..517f070196a 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -1,3 +1,5 @@ +"Dependency usage tracking for citations" + from sage.misc.all import tmp_filename from sage.env import SAGE_ROOT diff --git a/src/sage/misc/copying.py b/src/sage/misc/copying.py index d3406bd73c8..6fa1ff57d12 100644 --- a/src/sage/misc/copying.py +++ b/src/sage/misc/copying.py @@ -1,3 +1,5 @@ +"License" + import os import pager diff --git a/src/sage/misc/cython_c.pyx b/src/sage/misc/cython_c.pyx index 7f49842f785..f45f18b38a3 100644 --- a/src/sage/misc/cython_c.pyx +++ b/src/sage/misc/cython_c.pyx @@ -1,3 +1,5 @@ +"On-the-fly generation of compiled extensions" + import sage.misc.misc import sage.server.support diff --git a/src/sage/misc/derivative.pyx b/src/sage/misc/derivative.pyx index 0e821146e4b..60bb7c1e09b 100644 --- a/src/sage/misc/derivative.pyx +++ b/src/sage/misc/derivative.pyx @@ -18,22 +18,22 @@ Utility functions for making derivative() behave uniformly across Sage. To use these functions: - (1) attach the following method to your class: +1. attach the following method to your class:: def _derivative(self, var=None): [ should differentiate wrt the single variable var and return - result; var==None means attempt to differentiate wrt a `default' - variable. ] + result; var==None means attempt to differentiate wrt a 'default' + variable. ] - (2) from sage.misc.derivative import multi_derivative +2. from sage.misc.derivative import multi_derivative - (3) add the following method to your class: +3. add the following method to your class:: def derivative(self, *args): return multi_derivative(self, args) Then your object will support the standard parameter format for derivative(). -For example: +For example:: F.derivative(): diff wrt. default variable (calls F._derivative(None)) @@ -54,14 +54,8 @@ For example: For the precise specification see documentation for derivative_parse(). AUTHORS: - -- David Harvey (2008-02) -TODO: - -- This stuff probably belongs somewhere like sage/misc/misc_c.pyx. - The only reason it's in its own file here is because of some circular cimport - problems (can't cimport Integer to sage/misc/misc_c.pyx). For further - discussion see - http://codespeak.net/pipermail/cython-dev/2008-February/000057.html +- David Harvey (2008-02) """ @@ -70,45 +64,51 @@ from sage.rings.integer cimport Integer def derivative_parse(args): r""" - Translates a sequence consisting of `variables' and iteration counts into + Translates a sequence consisting of 'variables' and iteration counts into a single sequence of variables. INPUT: - args -- any iterable, interpreted as a sequence of `variables' and + + args -- any iterable, interpreted as a sequence of 'variables' and iteration counts. An iteration count is any integer type (python int or Sage Integer). Iteration counts must be non-negative. Any object which is not an integer is assumed to be a variable. OUTPUT: - A sequence, the `expanded' version of the input, defined as follows. + + A sequence, the 'expanded' version of the input, defined as follows. Read the input from left to right. If you encounter a variable V followed by an iteration count N, then output N copies of V. If V is not followed by an iteration count, output a single copy of V. If you encounter an iteration count N (not attached to a preceding variable), then output N copies of None. - Special case: if input is empty, output [None] (i.e. ``differentiate - once with respect to the default variable''). + Special case: if input is empty, output [None] (i.e. "differentiate + once with respect to the default variable"). Special case: if the input is a 1-tuple containing a single list, then the return value is simply that list. - EXAMPLES: + EXAMPLES:: + sage: x = var("x") sage: y = var("y") sage: from sage.misc.derivative import derivative_parse Differentiate twice with respect to x, then once with respect to y, - then once with respect to x: + then once with respect to x:: + sage: derivative_parse([x, 2, y, x]) [x, x, y, x] Differentiate twice with respect to x, then twice with respect to - the `default variable': + the 'default variable':: + sage: derivative_parse([x, 2, 2]) [x, x, None, None] - Special case with empty input list: + Special case with empty input list:: + sage: derivative_parse([]) [None] @@ -117,11 +117,13 @@ def derivative_parse(args): ... ValueError: derivative counts must be non-negative - Special case with single list argument provided: + Special case with single list argument provided:: + sage: derivative_parse(([x, y], )) [x, y] - If only the count is supplied: + If only the count is supplied:: + sage: derivative_parse([0]) [] sage: derivative_parse([1]) @@ -131,7 +133,8 @@ def derivative_parse(args): sage: derivative_parse([int(2)]) [None, None] - Various other cases: + Various other cases:: + sage: derivative_parse([x]) [x] sage: derivative_parse([x, x]) @@ -182,10 +185,12 @@ def multi_derivative(F, args): Calls F._derivative(var) for a sequence of variables specified by args. INPUT: + F -- any object with a _derivative(var) method. args -- any tuple that can be processed by derivative_parse(). - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.derivative import multi_derivative sage: R. = PolynomialRing(QQ) sage: f = x^3 * y^4 * z^5 @@ -198,6 +203,8 @@ def multi_derivative(F, args): sage: multi_derivative(f, (x, 2)) # like f.derivative(x, 2) 6*x*y^4*z^5 + :: + sage: R. = PolynomialRing(QQ) sage: f = x^4 + x^2 + 1 sage: multi_derivative(f, []) # like f.derivative() diff --git a/src/sage/misc/flatten.py b/src/sage/misc/flatten.py index c614696157a..cfae90fd3ac 100644 --- a/src/sage/misc/flatten.py +++ b/src/sage/misc/flatten.py @@ -1,17 +1,22 @@ +"Flatten nested lists" + import sys def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): """ Flattens a nested list. INPUT: - in_list -- a list or tuple - ltypes -- optional list of particular types to flatten - max_level -- the maximum level to flatten + + - in_list -- a list or tuple + - ltypes -- optional list of particular types to flatten + - max_level -- the maximum level to flatten OUTPUT: - a flat list of the entries of in_list - EXAMPLES: + a flat list of the entries of in_list + + EXAMPLES:: + sage: flatten([[1,1],[1],2]) [1, 1, 1, 2] sage: flatten([[1,2,3], (4,5), [[[1],[2]]]]) @@ -27,15 +32,18 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): In the following example, the vector isn't flattened because - it is not given in the ltypes input. + it is not given in the ltypes input. :: + sage: flatten((['Hi',2,vector(QQ,[1,2,3])],(4,5,6))) ['Hi', 2, (1, 2, 3), 4, 5, 6] - We give the vector type and then even the vector gets flattened: + We give the vector type and then even the vector gets flattened:: + sage: flatten((['Hi',2,vector(QQ,[1,2,3])], (4,5,6)), ltypes=(list, tuple,sage.modules.vector_rational_dense.Vector_rational_dense)) ['Hi', 2, 1, 2, 3, 4, 5, 6] - We flatten a finite field. + We flatten a finite field. :: + sage: flatten(GF(5)) [0, 1, 2, 3, 4] sage: flatten([GF(5)]) @@ -43,7 +51,8 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): sage: flatten([GF(5)], ltypes = (list, tuple, sage.rings.finite_rings.finite_field_prime_modn.FiniteField_prime_modn)) [0, 1, 2, 3, 4] - Degenerate cases: + Degenerate cases:: + sage: flatten([[],[]]) [] sage: flatten([[[]]]) diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 3e080d9dc0e..0b5da09b66e 100644 --- a/src/sage/misc/fpickle.pyx +++ b/src/sage/misc/fpickle.pyx @@ -9,7 +9,9 @@ import types, copy_reg, cPickle def code_ctor(*args): """ EXAMPLES: - This indirectly tests this function. + + This indirectly tests this function. :: + sage: def foo(a,b,c=10): return a+b+c sage: sage.misc.fpickle.reduce_code(foo.__code__) (, ...) @@ -20,7 +22,8 @@ def code_ctor(*args): def reduce_code(co): """ - EXAMPLES: + EXAMPLES:: + sage: def foo(N): return N+1 sage: sage.misc.fpickle.reduce_code(foo.__code__) (, ...) @@ -45,11 +48,15 @@ def pickle_function(func): work on functions that includes nested functions. INPUT: + func -- a Python function + OUTPUT: + a string - EXAMPLES: + EXAMPLES:: + sage: def f(N): return N+1 ... sage: g = pickle_function(f) @@ -62,7 +69,9 @@ def pickle_function(func): def unpickle_function(pickled): """ Unpickle a pickled function. + EXAMPLES: + sage: def f(N,M): return N*M ... sage: unpickle_function(pickle_function(f))(3,5) diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index fe013ae8619..fb7bd8463b9 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -87,7 +87,7 @@ cdef class _lazy_attribute(object): sage: src[0] 'def banner():\n' sage: lines - 78 + 82 """ from sage.misc.sageinspect import sage_getsourcelines return sage_getsourcelines(self.f) diff --git a/src/sage/misc/map_threaded.py b/src/sage/misc/map_threaded.py index 12140578405..c04841374ec 100644 --- a/src/sage/misc/map_threaded.py +++ b/src/sage/misc/map_threaded.py @@ -7,7 +7,8 @@ def map_threaded(function, sequence): Apply the function to the elements in the sequence by threading recursively through all sub-sequences in the sequence. - EXAMPLES: + EXAMPLES:: + sage: map_threaded(log, [[1,2], [3,e]]) [[0, log(2)], [log(3), 1]] sage: map_threaded(log, [(1,2), (3,e)]) @@ -18,13 +19,15 @@ def map_threaded(function, sequence): [[1, 4, 9, 25], [4, 100]] map_threaded also works on any object with an apply_map method, e.g., - on matrices: + on matrices:: + sage: map_threaded(lambda x: x^2, matrix([[1,2], [3,4]])) [ 1 4] [ 9 16] AUTHORS: - -- William Stein (2007-12); based on feedback from Peter Doyle. + + - William Stein (2007-12); based on feedback from Peter Doyle. """ if hasattr(sequence, 'apply_map'): return sequence.apply_map(function) diff --git a/src/sage/misc/multireplace.py b/src/sage/misc/multireplace.py index f1982a67d55..9874c094dee 100644 --- a/src/sage/misc/multireplace.py +++ b/src/sage/misc/multireplace.py @@ -1,3 +1,5 @@ +"multi_replace" + ########################################################################## # # multi_replace function diff --git a/src/sage/misc/parser.pyx b/src/sage/misc/parser.pyx index e43c72ddd87..3d08d1ae8df 100644 --- a/src/sage/misc/parser.pyx +++ b/src/sage/misc/parser.pyx @@ -6,7 +6,8 @@ complete control over what names are used (including dynamically creating variables) and how integer and floating point literals are created. AUTHOR: - -- Robert Bradshaw 2008-04 (initial version) + +- Robert Bradshaw 2008-04 (initial version) """ #***************************************************************************** @@ -38,7 +39,8 @@ def foo(*args, **kwds): This is a function for testing that simply returns the arguments and keywords passed into it. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import foo sage: foo(1, 2, a=3) ((1, 2), {'a': 3}) @@ -83,7 +85,8 @@ def token_to_str(int token): For speed reasons, tokens are integers. This function returns a string representation of a given token. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("+ 2") sage: token_to_str(t.next()) @@ -119,40 +122,49 @@ cdef class Tokenizer: The tokenizer wraps a string object, to tokenize a different string create a new tokenizer. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer sage: Tokenizer("1.5+2*3^4-sin(x)").test() ['FLOAT(1.5)', '+', 'INT(2)', '*', 'INT(3)', '^', 'INT(4)', '-', 'NAME(sin)', '(', 'NAME(x)', ')'] - The single character tokens are given by: + The single character tokens are given by:: + sage: Tokenizer("+-*/^(),=<>[]{}").test() ['+', '-', '*', '/', '^', '(', ')', ',', '=', '<', '>', '[', ']', '{', '}'] - Two-character comparisons accepted are: + Two-character comparisons accepted are:: + sage: Tokenizer("<= >= != == **").test() ['LESS_EQ', 'GREATER_EQ', 'NOT_EQ', '=', '^'] - Integers are strings of 0-9: + Integers are strings of 0-9:: + sage: Tokenizer("1 123 9879834759873452908375013").test() ['INT(1)', 'INT(123)', 'INT(9879834759873452908375013)'] - Floating point numbers can contain a single decimal point and possibly exponential notation: + Floating point numbers can contain a single decimal point and possibly exponential notation:: + sage: Tokenizer("1. .01 1e3 1.e-3").test() ['FLOAT(1.)', 'FLOAT(.01)', 'FLOAT(1e3)', 'FLOAT(1.e-3)'] - Note that negative signs are not attached to the token: + Note that negative signs are not attached to the token:: + sage: Tokenizer("-1 -1.2").test() ['-', 'INT(1)', '-', 'FLOAT(1.2)'] - Names are alphanumeric sequences not starting with a digit: + Names are alphanumeric sequences not starting with a digit:: + sage: Tokenizer("a a1 _a_24").test() ['NAME(a)', 'NAME(a1)', 'NAME(_a_24)'] - Anything else is an error: + Anything else is an error:: + sage: Tokenizer("&@~").test() ['ERROR', 'ERROR', 'ERROR'] - No attempt for correctness is made at this stage: + No attempt for correctness is made at this stage:: + sage: Tokenizer(") )( 5e5e5").test() [')', ')', '(', 'FLOAT(5e5)', 'NAME(e5)'] sage: Tokenizer("?$%").test() @@ -170,7 +182,8 @@ cdef class Tokenizer: Destructively read off the tokens in self, returning a list of string representations of the tokens. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer sage: t = Tokenizer("a b 3") sage: t.test() @@ -192,7 +205,8 @@ cdef class Tokenizer: """ Reset the tokenizer to a given position. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer sage: t = Tokenizer("a+b*c") sage: t.test() @@ -206,7 +220,8 @@ cdef class Tokenizer: sage: t.test() ['*', 'NAME(c)'] - No care is taken to make sure we don't jump in the middle of a token: + No care is taken to make sure we don't jump in the middle of a token:: + sage: t = Tokenizer("12345+a") sage: t.test() ['INT(12345)', '+', 'NAME(a)'] @@ -310,7 +325,8 @@ cdef class Tokenizer: """ Returns the next token in the string. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("a+3") sage: token_to_str(t.next()) @@ -332,7 +348,8 @@ cdef class Tokenizer: """ Returns the last token seen. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("3a") sage: token_to_str(t.next()) @@ -351,7 +368,8 @@ cdef class Tokenizer: Returns the next token that will be encountered, without changing the state of self. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("a+b") sage: token_to_str(t.peek()) @@ -377,7 +395,8 @@ cdef class Tokenizer: Currently, one can only backtrack once. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("a+b") sage: token_to_str(t.next()) @@ -399,7 +418,8 @@ cdef class Tokenizer: """ Return the actual contents of the last token. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Tokenizer, token_to_str sage: t = Tokenizer("a - 1e5") sage: token_to_str(t.next()) @@ -429,19 +449,22 @@ cdef class Parser: Create a symbolic expression parser. INPUT: - make_int -- callable object to construct integers from strings (default int) - make_float -- callable object to construct real numbers from strings (default float) - make_var -- callable object to construct variables from strings (default str) - this may also be a dictionary of variable names - make_function -- callable object to construct callable functions from strings - this may also be a dictionary - implicit_multiplication -- whether or not to accept implicit multiplication + + - make_int -- callable object to construct integers from strings (default int) + - make_float -- callable object to construct real numbers from strings (default float) + - make_var -- callable object to construct variables from strings (default str) + this may also be a dictionary of variable names + - make_function -- callable object to construct callable functions from strings + this may also be a dictionary + - implicit_multiplication -- whether or not to accept implicit multiplication OUTPUT: + The evaluated expression tree given by the string, where the above functions are used to create the leaves of this tree. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser sage: p = Parser() sage: p.parse("1+2") @@ -480,7 +503,8 @@ cdef class Parser: """ Parse the given string. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser sage: p = Parser(make_var=var) sage: p.parse("E = m c^2") @@ -501,7 +525,8 @@ cdef class Parser: """ Parse an expression. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser sage: p = Parser(make_var=var) sage: p.parse_expression('a-3b^2') @@ -517,7 +542,8 @@ cdef class Parser: """ Parse a (possibly nested) set of lists and tuples. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser sage: p = Parser(make_var=var) sage: p.parse_sequence("1,2,3") @@ -539,7 +565,8 @@ cdef class Parser: """ Parse a matrix - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_matrix(Tokenizer("([a,0],[0,a])")) @@ -566,7 +593,8 @@ cdef class Parser: """ Parse a (possibly nested) set of lists and tuples. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_sequence(Tokenizer("[1+2,0]")) @@ -610,7 +638,8 @@ cdef class Parser: """ Parse a list of items. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_list(Tokenizer("[1+2, 1e3]")) @@ -631,7 +660,8 @@ cdef class Parser: """ Parse a tuple of items. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_tuple(Tokenizer("( (), (1), (1,), (1,2), (1,2,3), (1+2)^2, )")) @@ -667,7 +697,8 @@ cdef class Parser: This is the top-level node called by the \code{parse} function. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_eqn(Tokenizer("1+a")) @@ -709,7 +740,8 @@ cdef class Parser: """ Parse a list of one or more terms. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_expr(Tokenizer("a+b")) @@ -742,7 +774,8 @@ cdef class Parser: """ Parse a single term (consisting of one or more factors). - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var) sage: p.p_term(Tokenizer("a*b")) @@ -782,7 +815,8 @@ cdef class Parser: Parse a single factor, which consists of any number of unary +/- and a power. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: R. = ZZ[['t']] sage: p = Parser(make_var={'t': t}) @@ -807,7 +841,8 @@ cdef class Parser: """ Parses a power. Note that exponentiation groups right to left. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: R. = ZZ[['t']] sage: p = Parser(make_var={'t': t}) @@ -850,7 +885,8 @@ cdef class Parser: """ Parse an atom. This is either a parenthesized expression, a function call, or a literal name/int/float. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser(make_var=var, make_function={'sin': sin}) sage: p.p_atom(Tokenizer("1")) @@ -903,7 +939,8 @@ cdef class Parser: """ Returns a list, dict pair. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import Parser, Tokenizer sage: p = Parser() sage: p.p_args(Tokenizer("1,2,a=3")) @@ -982,7 +1019,8 @@ cdef class LookupNameMaker: It takes a dictionary of names, and an (optional) callable to use when the given name is not found in the dictionary. - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.parser import LookupNameMaker sage: maker = LookupNameMaker({'pi': pi}, var) sage: maker('pi') @@ -997,7 +1035,8 @@ cdef class LookupNameMaker: def __call__(self, name): """ - TESTS: + TESTS:: + sage: from sage.misc.parser import LookupNameMaker sage: maker = LookupNameMaker({'a': x}, str) sage: maker('a') diff --git a/src/sage/misc/python.py b/src/sage/misc/python.py index 39ad8821fcf..87afc2f0a7e 100644 --- a/src/sage/misc/python.py +++ b/src/sage/misc/python.py @@ -1,19 +1,24 @@ +"Evaluating Python code without any preparsing" + class Python: """ Allows for evaluating a chunk of code without any preparsing. """ + def eval(self, x, globals, locals=None): - """ + r""" Evaluate x with given globals; locals is completely ignored. This is specifically meant for evaluating code blocks with - \code{%python} in the notebook. + ``%python`` in the notebook. INPUT: + x -- a string globals -- a dictionary locals -- completely IGNORED - EXAMPLES: + EXAMPLES:: + sage: from sage.misc.python import Python sage: python = Python() sage: python.eval('2+2', globals()) @@ -21,7 +26,8 @@ def eval(self, x, globals, locals=None): '' Any variables that are set during evaluation of the block - will propagate to the globals dictionary. + will propagate to the globals dictionary. :: + sage: python.eval('a=5\nb=7\na+b', globals()) 12 '' @@ -30,7 +36,8 @@ def eval(self, x, globals, locals=None): The locals variable is ignored -- it is there only for completeness. It is ignored since otherwise the following - won't work: + won't work:: + sage: python.eval("def foo():\n return 'foo'\nprint foo()\ndef mumble():\n print 'mumble',foo()\nmumble()", globals()) foo mumble foo diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index b5c7825a664..ddc333484e0 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -1,3 +1,5 @@ +"get_remote_file" + import os, sys def get_remote_file(filename, verbose=True): diff --git a/src/sage/misc/reset.pyx b/src/sage/misc/reset.pyx index 5a3951036df..b3fd4109602 100644 --- a/src/sage/misc/reset.pyx +++ b/src/sage/misc/reset.pyx @@ -1,3 +1,5 @@ +"Interpreter reset" + import sys # Exclude these from the reset command. diff --git a/src/sage/misc/sh.py b/src/sage/misc/sh.py index 64eeda49f84..a16c987731f 100644 --- a/src/sage/misc/sh.py +++ b/src/sage/misc/sh.py @@ -1,3 +1,5 @@ +"Evaluating shell scripts" + import os @@ -5,13 +7,13 @@ class Sh: r""" Evaluates a shell script and returns the output. - To use this from the notebook type \code{\%sh} at the beginning of + To use this from the notebook type ``sh`` at the beginning of the input cell. The working directory is then the (usually temporary) directory where the Sage worksheet process is executing. """ def eval(self, code, globals=None, locals=None): - """ + r""" This is difficult to test because the output goes to the screen rather than being captured by the doctest program, so the following really only tests that the command doesn't bomb, diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 712b7944539..6c13f92a80a 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -467,10 +467,10 @@ def deprecated_callable_import(trac_number, module_name, globs, locs, fromlist, - ``locs`` -- dictionary. The ``locals()`` from where this is being called. - - ``param fromlist``: -- list of strings. The list the names of the + - ``fromlist`` -- list of strings. The list the names of the callables to deprecate - - ``message`` --` string. Message to display when the deprecated functions are called. + - ``message`` -- string. Message to display when the deprecated functions are called. .. note:: diff --git a/src/sage/structure/coerce_exceptions.py b/src/sage/structure/coerce_exceptions.py index 5f5e2b7beb1..1764d800a3d 100644 --- a/src/sage/structure/coerce_exceptions.py +++ b/src/sage/structure/coerce_exceptions.py @@ -1,3 +1,5 @@ +"Exceptions raised by the coercion model" + ############################################################################### # SAGE: System for Algebra and Geometry Experimentation # Copyright (C) 2009 Robert Bradshaw diff --git a/src/sage/structure/factorization_integer.py b/src/sage/structure/factorization_integer.py index e9ed4a2f28f..dac3fed52e0 100644 --- a/src/sage/structure/factorization_integer.py +++ b/src/sage/structure/factorization_integer.py @@ -1,3 +1,5 @@ +"IntegerFactorization objects" + from sage.structure.factorization import Factorization from sage.rings.integer_ring import ZZ diff --git a/src/sage/structure/generators.pyx b/src/sage/structure/generators.pyx index ec7825ab973..b9ecd1f90d4 100644 --- a/src/sage/structure/generators.pyx +++ b/src/sage/structure/generators.pyx @@ -1,7 +1,5 @@ """ -This module implements Generators, a type of object that represents (algebraic) generators of a Sage object. - - +(Algebraic) generators of a Sage object. """ from sage.structure.sage_object cimport SageObject diff --git a/src/sage/structure/misc.pyx b/src/sage/structure/misc.pyx index a5e188409e5..e11c38b7d81 100644 --- a/src/sage/structure/misc.pyx +++ b/src/sage/structure/misc.pyx @@ -1,13 +1,17 @@ +"Miscellaneous utilities" + from sage.misc.sage_itertools import unique_merge def is_extension_type(cls): """ INPUT: - - cls: a class + + - cls: a class Tests whether cls is an extension type (int, list, cython compiled classes, ...) - EXAMPLES + EXAMPLES:: + sage: from sage.structure.parent import is_extension_type sage: is_extension_type(int) True @@ -33,14 +37,14 @@ cdef class AttributeErrorMessage: """ Tries to emulate the standard Python ``AttributeError`` message. - NOTE: + .. note:: - The typical fate of an attribute error is being caught. Hence, - under normal circumstances, nobody will ever see the error - message. The idea for this class is to provide an object that - is fast to create and whose string representation is an attribute - error's message. That string representation is only created if - someone wants to see it. + The typical fate of an attribute error is being caught. Hence, + under normal circumstances, nobody will ever see the error + message. The idea for this class is to provide an object that + is fast to create and whose string representation is an attribute + error's message. That string representation is only created if + someone wants to see it. EXAMPLES:: @@ -60,8 +64,7 @@ cdef class AttributeErrorMessage: By :trac:`14100`, the attribute errors raised on elements and parents are unique objects. The error message of this unique error object is changed - inplace. This is for reasons of efficiency. - :: + inplace. This is for reasons of efficiency. :: sage: try: ....: 1.__bla diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index ce5b709bc21..e32b0a72711 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -1,3 +1,5 @@ +"Precision management for non-exact objects" + import sage.rings.integer class Nonexact: @@ -7,7 +9,7 @@ def __init__(self, prec=20): def default_prec(self): r""" Return the default precision for self. Use - \code{set_default_prec} to set the default precision. + ``set_default_prec`` to set the default precision. """ try: return self.__default_prec diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index 771bb26abc5..156b0da0815 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -1,3 +1,5 @@ +"Global proof preferences" + from sage.structure.sage_object import SageObject class _ProofPref(SageObject): @@ -20,14 +22,17 @@ def arithmetic(self, t = None): Controls the default proof strategy for integer arithmetic algorithms (such as primality testing). INPUT: + t -- boolean or None OUTPUT: + If t == True, requires integer arithmetic operations to (by default) return results that are true unconditionally: the correctness will not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. If t == False, allows integer arithmetic operations to (by default) return results that may depend on unproven conjectures or on probabilistic algorithms. Such algorithms often have a substantial speed improvement over those requiring proof. If t is None, returns the integer arithmetic proof status. - EXAMPLES: + EXAMPLES:: + sage: proof.arithmetic() True sage: proof.arithmetic(False) @@ -46,14 +51,17 @@ def elliptic_curve(self, t = None): Controls the default proof strategy for elliptic curve algorithms. INPUT: + t -- boolean or None OUTPUT: + If t == True, requires elliptic curve algorithms to (by default) return results that are true unconditionally: the correctness will not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. If t == False, allows elliptic curve algorithms to (by default) return results that may depend on unproven conjectures or on probabilistic algorithms. Such algorithms often have a substantial speed improvement over those requiring proof. If t is None, returns the current elliptic curve proof status. - EXAMPLES: + EXAMPLES:: + sage: proof.elliptic_curve() True sage: proof.elliptic_curve(False) @@ -72,14 +80,17 @@ def linear_algebra(self, t = None): Controls the default proof strategy for linear algebra algorithms. INPUT: + t -- boolean or None OUTPUT: + If t == True, requires linear algebra algorithms to (by default) return results that are true unconditionally: the correctness will not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. If t == False, allows linear algebra algorithms to (by default) return results that may depend on unproven conjectures or on probabilistic algorithms. Such algorithms often have a substantial speed improvement over those requiring proof. If t is None, returns the current linear algebra proof status. - EXAMPLES: + EXAMPLES:: + sage: proof.linear_algebra() True sage: proof.linear_algebra(False) @@ -98,14 +109,17 @@ def number_field(self, t = None): Controls the default proof strategy for number field algorithms. INPUT: + t -- boolean or None OUTPUT: + If t == True, requires number field algorithms to (by default) return results that are true unconditionally: the correctness will not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. If t == False, allows number field algorithms to (by default) return results that may depend on unproven conjectures or on probabilistic algorithms. Such algorithms often have a substantial speed improvement over those requiring proof. If t is None, returns the current number field proof status. - EXAMPLES: + EXAMPLES:: + sage: proof.number_field() True sage: proof.number_field(False) @@ -124,14 +138,17 @@ def polynomial(self, t = None): Controls the default proof strategy for polynomial algorithms. INPUT: + t -- boolean or None OUTPUT: + If t == True, requires polynomial algorithms to (by default) return results that are true unconditionally: the correctness will not depend on an algorithm with a nonzero probability of returning an incorrect answer or on the truth of any unproven conjectures. If t == False, allows polynomial algorithms to (by default) return results that may depend on unproven conjectures or on probabilistic algorithms. Such algorithms often have a substantial speed improvement over those requiring proof. If t is None, returns the current polynomial proof status. - EXAMPLES: + EXAMPLES:: + sage: proof.polynomial() True sage: proof.polynomial(False) @@ -152,7 +169,8 @@ def get_flag(t = None, subsystem = None): """ Used for easily determining the correct proof flag to use. - EXAMPLES: + EXAMPLES:: + sage: from sage.structure.proof.proof import get_flag sage: get_flag(False) False diff --git a/src/sage_setup/autogen/interpreters.py b/src/sage_setup/autogen/interpreters.py index c6ac26fa1fe..eb4abf0cbbc 100644 --- a/src/sage_setup/autogen/interpreters.py +++ b/src/sage_setup/autogen/interpreters.py @@ -41,12 +41,12 @@ To make this work, the interpreter back-end is divided into three parts: - 1. The interpreter itself, in C or C++. +1. The interpreter itself, in C or C++. - 2. The wrapper, which is a Cython object holding the - constants, code, etc., and which actually calls the interpreter. +2. The wrapper, which is a Cython object holding the + constants, code, etc., and which actually calls the interpreter. - 3. The code generator. +3. The code generator. We generate parts 1 and 2. The code generator is table-driven, and we generate the tables for the code generator. @@ -126,8 +126,9 @@ def indent_lines(n, text): r""" INPUTS: - n -- indentation amount - text -- text to indent + + - n -- indentation amount + - text -- text to indent Indents each line in text by n spaces. @@ -1195,11 +1196,13 @@ def is_stack(self): It would be nicer to make this object-oriented somehow, so that the code generator called MemoryChunk methods instead of - using + using:: + if ch.is_stack(): ... hardcoded stack code else: ... hardcoded non-stack code + but that hasn't been done yet. EXAMPLES:: @@ -1341,10 +1344,10 @@ class members. class MemoryChunkArguments(MemoryChunkLonglivedArray): r""" MemoryChunkArguments is a subtype of MemoryChunkLonglivedArray, - for dealing with arguments to the wrapper's __call__ method. + for dealing with arguments to the wrapper's ``__call__`` method. - Currently the __call__ method is declared to take a varargs - *args argument tuple. We assume that the MemoryChunk named 'args' + Currently the ``__call__`` method is declared to take a varargs + `*args` argument tuple. We assume that the MemoryChunk named `args` will deal with that tuple. """ @@ -1911,9 +1914,11 @@ class InstrSpec(object): calls, you may need to use a temporary variable. Here's an example of this issue. Suppose you want to make an - instruction that does ``out = a+b*c``. You write code like this: + instruction that does ``out = a+b*c``. You write code like this:: + out = b*c out = a+out + But out will actually share the same storage as a; so the first line modifies a, and you actually end up computing 2*(b+c). The fix is to only write to the output once, at the very end of your From a7cbb88852ceefff65e421e75c0479bcd554ce26 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 16 Apr 2015 09:40:30 +0200 Subject: [PATCH 298/665] Remove _cmp_c_impl and _richcmp_c_impl --- .../coercion_and_categories.rst | 30 ++++-- .../free_algebra_element_letterplace.pyx | 2 +- .../quatalg/quaternion_algebra_element.pyx | 4 +- src/sage/categories/morphism.pyx | 4 +- src/sage/coding/binary_code.pxd | 2 +- src/sage/coding/binary_code.pyx | 10 +- src/sage/combinat/combinat.py | 7 +- src/sage/combinat/crystals/letters.pyx | 4 +- src/sage/combinat/root_system/weyl_group.py | 6 +- src/sage/combinat/set_partition.py | 4 +- src/sage/geometry/toric_lattice_element.pyx | 2 +- src/sage/groups/braid.py | 9 +- src/sage/groups/libgap_wrapper.pyx | 2 +- src/sage/groups/matrix_gps/group_element.py | 4 +- .../semimonomial_transformation.pxd | 4 +- .../semimonomial_transformation.pyx | 2 +- src/sage/libs/gap/element.pyx | 6 +- src/sage/libs/pari/gen.pyx | 4 +- src/sage/matrix/docs.py | 2 +- src/sage/matrix/matrix0.pyx | 2 +- src/sage/matrix/matrix_cyclo_dense.pyx | 6 +- src/sage/matrix/matrix_dense.pyx | 2 +- src/sage/matrix/matrix_double_dense.pyx | 2 +- src/sage/matrix/matrix_generic_dense.pyx | 2 +- src/sage/matrix/matrix_generic_sparse.pyx | 2 +- src/sage/matrix/matrix_integer_dense.pyx | 4 +- src/sage/matrix/matrix_integer_sparse.pyx | 4 +- src/sage/matrix/matrix_mod2_dense.pyx | 4 +- src/sage/matrix/matrix_mod2e_dense.pyx | 2 +- .../matrix/matrix_modn_dense_template.pxi | 2 +- src/sage/matrix/matrix_modn_sparse.pyx | 4 +- src/sage/matrix/matrix_rational_dense.pyx | 6 +- src/sage/matrix/matrix_rational_sparse.pyx | 4 +- src/sage/matrix/matrix_sparse.pyx | 2 +- src/sage/misc/cachefunc.pyx | 4 +- .../modular/arithgroup/arithgroup_element.pyx | 2 +- src/sage/modules/fg_pid/fgp_morphism.py | 6 +- src/sage/modules/free_module_element.pyx | 4 +- src/sage/modules/matrix_morphism.py | 4 +- src/sage/modules/vector_integer_dense.pyx | 2 +- src/sage/modules/vector_mod2_dense.pyx | 2 +- src/sage/modules/vector_modn_dense.pyx | 2 +- src/sage/modules/vector_rational_dense.pyx | 2 +- src/sage/numerical/linear_functions.pxd | 3 - src/sage/numerical/linear_functions.pyx | 14 +-- src/sage/numerical/linear_tensor_element.pxd | 12 +-- src/sage/numerical/linear_tensor_element.pyx | 9 +- src/sage/rings/complex_double.pyx | 10 +- src/sage/rings/complex_interval.pyx | 4 +- src/sage/rings/complex_number.pyx | 2 +- .../rings/finite_rings/element_givaro.pyx | 2 +- .../rings/finite_rings/element_ntl_gf2e.pyx | 2 +- .../rings/finite_rings/element_pari_ffelt.pyx | 2 +- .../rings/finite_rings/hom_finite_field.pxd | 2 - src/sage/rings/finite_rings/integer_mod.pyx | 6 +- src/sage/rings/fraction_field_FpT.pyx | 2 +- src/sage/rings/fraction_field_element.pyx | 2 +- .../function_field/function_field_element.pyx | 4 +- src/sage/rings/integer.pyx | 2 +- src/sage/rings/integer_ring.pyx | 5 +- .../rings/laurent_series_ring_element.pyx | 2 +- src/sage/rings/morphism.pyx | 6 +- .../rings/multi_power_series_ring_element.py | 4 +- src/sage/rings/number_field/morphism.py | 6 +- .../number_field/number_field_element.pyx | 2 +- .../number_field_element_quadratic.pyx | 4 +- src/sage/rings/padics/morphism.pxd | 3 - src/sage/rings/padics/morphism.pyx | 2 +- .../rings/padics/padic_ZZ_pX_FM_element.pyx | 2 +- .../rings/padics/padic_generic_element.pxd | 1 - .../rings/padics/padic_generic_element.pyx | 2 +- .../rings/polynomial/laurent_polynomial.pyx | 4 +- .../polynomial/multi_polynomial_element.py | 29 ++--- .../multi_polynomial_libsingular.pxd | 5 - .../multi_polynomial_libsingular.pyx | 6 +- .../multi_polynomial_ring_generic.pxd | 3 - .../multi_polynomial_ring_generic.pyx | 2 +- src/sage/rings/polynomial/pbori.pyx | 4 +- src/sage/rings/polynomial/plural.pxd | 2 - src/sage/rings/polynomial/plural.pyx | 2 +- .../rings/polynomial/polynomial_element.pyx | 2 +- .../rings/polynomial/polynomial_template.pxi | 2 +- .../rings/polynomial/polynomial_zz_pex.pyx | 2 +- src/sage/rings/power_series_ring_element.pyx | 2 +- src/sage/rings/rational.pyx | 2 +- src/sage/rings/real_arb.pyx | 2 +- src/sage/rings/real_double.pyx | 2 +- src/sage/rings/real_lazy.pyx | 2 +- src/sage/rings/real_mpfi.pyx | 4 +- src/sage/rings/real_mpfr.pyx | 2 +- .../rings/semirings/tropical_semiring.pyx | 2 +- .../elliptic_curves/ell_curve_isogeny.py | 12 +-- .../elliptic_curves/weierstrass_morphism.py | 59 +++++------ src/sage/schemes/generic/morphism.py | 4 +- src/sage/schemes/toric/morphism.py | 4 +- src/sage/structure/element.pxd | 8 +- src/sage/structure/element.pyx | 100 +++++++----------- src/sage/structure/list_clone.pyx | 4 +- src/sage/structure/parent.pxd | 3 +- src/sage/structure/parent.pyx | 27 +++-- src/sage/structure/parent_base.pyx | 5 - src/sage/structure/parent_old.pxd | 9 -- src/sage/structure/parent_old.pyx | 79 -------------- src/sage/symbolic/expression.pyx | 4 +- 104 files changed, 276 insertions(+), 424 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 72c082d361f..5e961400ed0 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -131,7 +131,6 @@ This base class provides a lot more methods than a general parent:: '_one_element', '_pseudo_fraction_field', '_random_nonzero_element', - '_richcmp', '_unit_ideal', '_zero_element', '_zero_ideal', @@ -311,10 +310,15 @@ considerations: etc. **We do not override the default double underscore __add__, __mul__**, since otherwise, we could not use Sage's coercion model. -- In the single underscore methods and in ``__cmp__``, we can assume that - *both arguments belong to the same parent*. This is one benefit of the - coercion model. Note that ``__cmp__`` should be provided, since otherwise - comparison does not work in the way expected in Python:: +- Comparisons can be implemented using ``_cmp_``. This automatically + makes the relational operators like ``==`` and ``<`` work. In order + to support the Python ``cmp()`` function, it is safest to define both + ``_cmp_`` and ``__cmp__`` (because ``__cmp__`` is not inherited if + other comparison operators or ``__hash__`` are defined). Of course you + can just do ``__cmp__ = _cmp_``. + + Note that ``_cmp_`` should be provided, since otherwise comparison + does not work:: sage: class Foo(sage.structure.element.Element): ....: def __init__(self, parent, x): @@ -326,7 +330,11 @@ considerations: sage: cmp(a,b) Traceback (most recent call last): ... - NotImplementedError: BUG: sort algorithm for elements of 'None' not implemented + NotImplementedError: comparison not implemented for + +- In the single underscore methods, we can assume that + *both arguments belong to the same parent*. + This is one benefit of the coercion model. - When constructing new elements as the result of arithmetic operations, we do not directly name our class, but we use ``self.__class__``. Later, this will @@ -360,8 +368,9 @@ This gives rise to the following code:: ....: return self.d ....: def _repr_(self): ....: return "(%s):(%s)"%(self.n,self.d) - ....: def __cmp__(self, other): + ....: def _cmp_(self, other): ....: return cmp(self.n*other.denominator(), other.numerator()*self.d) + ....: __cmp__ = _cmp_ ....: def _add_(self, other): ....: C = self.__class__ ....: D = self.d*other.denominator() @@ -1840,8 +1849,13 @@ Appendix: The complete code # into the same parent, which is a fraction field. Hence, we # are allowed to use the denominator() and numerator() methods # on the second argument. - def __cmp__(self, other): + def _cmp_(self, other): return cmp(self.n*other.denominator(), other.numerator()*self.d) + + # Support for cmp() (in this example, we don't define __hash__ + # so this is not strictly needed) + __cmp__ = _cmp_ + # Arithmetic methods, single underscore. We can assume that both # arguments are coerced into the same parent. # We return instances of self.__class__, because self.__class__ will diff --git a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx index d27596372f5..98f7918e64c 100644 --- a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx @@ -471,7 +471,7 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ Auxiliary method for comparison. diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 17d1c2f9ae6..a8d94079714 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -371,7 +371,7 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): """ return self._do_print(self[0], self[1], self[2], self[3]) - cdef int _cmp_c_impl(self, sage.structure.element.Element right) except -2: + cpdef int _cmp_(self, sage.structure.element.Element right) except -2: """ Comparing elements. @@ -924,7 +924,7 @@ cdef class QuaternionAlgebraElement_rational_field(QuaternionAlgebraElement_abst """ return bool(mpz_sgn(self.x) or mpz_sgn(self.y) or mpz_sgn(self.z) or mpz_sgn(self.w)) - cdef int _cmp_c_impl(self, sage.structure.element.Element _right) except -2: + cpdef int _cmp_(self, sage.structure.element.Element _right) except -2: """ Compare two quaternions. The comparison is fairly arbitrary -- first the denominators are compared and if equal then each diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index 32263ba69fe..41b05bb9b0a 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -349,7 +349,7 @@ cdef class Morphism(Map): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: if left is right: return 0 domain = left.domain() c = cmp(domain, right.domain()) @@ -362,7 +362,7 @@ cdef class Morphism(Map): c = cmp(left(x), right(x)) if c: return c except (AttributeError, NotImplementedError): - raise NotImplementedError + raise NotImplementedError("comparison not implemented for %r"%type(left)) cdef class FormalCoercionMorphism(Morphism): diff --git a/src/sage/coding/binary_code.pxd b/src/sage/coding/binary_code.pxd index 84b55966825..0af2e57aa82 100644 --- a/src/sage/coding/binary_code.pxd +++ b/src/sage/coding/binary_code.pxd @@ -87,7 +87,7 @@ cdef class PartitionStack: cdef int sort_wds(self, int, int) cdef int refine(self, int, int *, int, BinaryCode, int *) cdef void clear(self, int) - cdef int cmp(self, PartitionStack, BinaryCode) + cpdef int cmp(self, PartitionStack, BinaryCode) cdef int find_basis(self, int *) cdef void get_permutation(self, PartitionStack, int *, int *) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 2d3618e0a06..9319bf5056d 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -2853,9 +2853,9 @@ cdef class PartitionStack: self.col_percolate(j, i) j = i + 1 - def _cmp(self, other, C): + cpdef int cmp(self, PartitionStack other, BinaryCode CG): """ - EXAMPLE:: + EXAMPLES:: sage: import sage.coding.binary_code sage: from sage.coding.binary_code import * @@ -2890,13 +2890,9 @@ cdef class PartitionStack: 1224 sage: Q._is_discrete(4) 1 - sage: Q._cmp(P, B) + sage: Q.cmp(P, B) 0 - """ - return self.cmp(other, C) - - cdef int cmp(self, PartitionStack other, BinaryCode CG): cdef int *self_wd_ents = self.wd_ents cdef codeword *CG_words = CG.words cdef int i, j, l, m, span = 1, ncols = self.ncols, nwords = self.nwords diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 05f7ecc1d17..970cb7fce9b 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -924,14 +924,13 @@ def __cmp__(self, other): sage: from sage.structure.element import Element sage: class Bar(Element, CombinatorialObject): - ... def __init__(self, l): - ... CombinatorialObject.__init__(self, l) - ... + ....: def __init__(self, l): + ....: CombinatorialObject.__init__(self, l) sage: L = [Bar([4-i]) for i in range(4)] sage: sorted(L, cmp) Traceback (most recent call last): ... - NotImplementedError: BUG: sort algorithm for elements of 'None' not implemented + NotImplementedError: comparison not implemented for """ if isinstance(other, CombinatorialObject): return cmp(self._list, other._list) diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index 9e1c4481455..a7fa5decdf0 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -431,7 +431,7 @@ cdef class Letter(Element): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Return ``True`` if ``left`` compares with ``right`` based on ``op``. @@ -1311,7 +1311,7 @@ cdef class LetterTuple(Element): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Check comparison between ``left`` and ``right`` based on ``op`` diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index e290114477c..6dc3679ab7f 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -795,7 +795,7 @@ def __eq__(self, other): self._parent == other._parent and \ self.__matrix == other.__matrix - def __cmp__(self, other): + def _cmp_(self, other): """ EXAMPLES:: @@ -806,12 +806,12 @@ def __cmp__(self, other): sage: s[1] == s[2] False """ - if self.__class__ != other.__class__: - return cmp(self.__class__, other.__class__) if self._parent.cartan_type() != other._parent.cartan_type(): return cmp(self._parent.cartan_type(), other._parent.cartan_type()) return cmp(self.matrix(), other.matrix()) + __cmp__ = _cmp_ + def action(self, v): """ Returns the action of self on the vector v. diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index c437d8f36db..066863d76e0 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -315,7 +315,7 @@ def __ge__(self, y): """ return self.__eq__(y) or self.__gt__(y) - def __cmp__(self, y): + def _cmp_(self, y): """ Return the result of ``cmp``. @@ -337,6 +337,8 @@ def __cmp__(self, y): return 1 return 0 + __cmp__ = _cmp_ + def __mul__(self, other): r""" The product of the set partitions ``self`` and ``other``. diff --git a/src/sage/geometry/toric_lattice_element.pyx b/src/sage/geometry/toric_lattice_element.pyx index 04c8d4cb32f..2a39ad678c2 100644 --- a/src/sage/geometry/toric_lattice_element.pyx +++ b/src/sage/geometry/toric_lattice_element.pyx @@ -215,7 +215,7 @@ cdef class ToricLatticeElement(Vector_integer_dense): except AttributeError: return cmp(PL, PR) # Now use the real comparison of vectors - return self._cmp_c_impl(right) + return self._cmp_(right) # For some reason, vectors work just fine without redefining this function # from the base class, but if it is not here, we get "unhashable type"... diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 238cc6d170a..007d2407e48 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -90,8 +90,7 @@ class Braid(FinitelyPresentedGroupElement): sage: B((1, 2, -3, -2)) s0*s1*s2^-1*s1^-1 """ - - def __cmp__(self, other): + def _cmp_(self, other): """ Compare ``self`` and ``other`` @@ -102,9 +101,9 @@ def __cmp__(self, other): sage: c = B([2, 1, 2]) sage: b == c #indirect doctest True - sage: b.__cmp__(c^(-1)) + sage: b._cmp_(c^(-1)) -1 - sage: B([]).__cmp__(B.one()) + sage: B([])._cmp_(B.one()) 0 """ if self.Tietze()==other.Tietze(): @@ -113,6 +112,8 @@ def __cmp__(self, other): nfother = map(lambda i: i.Tietze(), other.left_normal_form()) return cmp(nfself, nfother) + __cmp__ = _cmp_ + def __hash__(self): r""" Return a hash value for ``self``. diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index a9614415f48..f4db5acfeff 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -556,7 +556,7 @@ cdef class ElementLibGAP(MultiplicativeGroupElement): P = left.parent() return P.element_class(P, left.gap() * right.gap()) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ This method implements comparison. diff --git a/src/sage/groups/matrix_gps/group_element.py b/src/sage/groups/matrix_gps/group_element.py index 972157a5033..d77e6938c8c 100644 --- a/src/sage/groups/matrix_gps/group_element.py +++ b/src/sage/groups/matrix_gps/group_element.py @@ -182,7 +182,7 @@ def _act_on_(self, x, self_on_left): except TypeError: return None - def __cmp__(self, other): + def _cmp_(self, other): """ EXAMPLES:: @@ -198,6 +198,8 @@ def __cmp__(self, other): """ return cmp(self.matrix(), other.matrix()) + __cmp__ = _cmp_ + def list(self): """ Return list representation of this matrix. diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pxd b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pxd index 11167d5ee61..637b785e958 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pxd +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pxd @@ -5,6 +5,4 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): cdef tuple v cdef object perm, alpha - cpdef MonoidElement _mul_(left, MonoidElement _right) - cdef int _cmp_c_impl(left, Element _right) except -2 - cdef _new_c(self) \ No newline at end of file + cdef _new_c(self) diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx index fadead2ee5f..d54d7cd9e87 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation.pyx @@ -260,7 +260,7 @@ cdef class SemimonomialTransformation(MultiplicativeGroupElement): """ return ( self)._cmp(right) - cdef int _cmp_c_impl(left, Element _right) except -2: + cpdef int _cmp_(left, Element _right) except -2: cdef SemimonomialTransformation right = _right return cmp([left.v, left.perm, left.get_autom()], [right.v, right.perm, right.get_autom()]) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 3aa3cd97b64..3f68ce70746 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -576,7 +576,7 @@ cdef class GapElement(RingElement): """ return hash(str(self)) - cdef _richcmp_c_impl(self, Element other, int op): + cpdef _richcmp_(self, Element other, int op): """ Compare ``self`` with ``other``. @@ -645,7 +645,7 @@ cdef class GapElement(RingElement): """ Compare ``self`` with ``other``. - Helper for :meth:`_richcmp_c_impl` + Helper for :meth:`_richcmp_` EXAMPLES:: @@ -671,7 +671,7 @@ cdef class GapElement(RingElement): """ Compare ``self`` with ``other``. - Helper for :meth:`_richcmp_c_impl` + Helper for :meth:`_richcmp_` EXAMPLES:: diff --git a/src/sage/libs/pari/gen.pyx b/src/sage/libs/pari/gen.pyx index 6d595a3b323..985d3ba2585 100644 --- a/src/sage/libs/pari/gen.pyx +++ b/src/sage/libs/pari/gen.pyx @@ -1053,7 +1053,7 @@ cdef class gen(gen_auto): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right`` using ``op``. @@ -1129,7 +1129,7 @@ cdef class gen(gen_auto): def __cmp__(left, right): return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Compare ``left`` and ``right``. diff --git a/src/sage/matrix/docs.py b/src/sage/matrix/docs.py index 7db24a0057c..d3e17fa3b5c 100644 --- a/src/sage/matrix/docs.py +++ b/src/sage/matrix/docs.py @@ -393,7 +393,7 @@ class derived from Matrix). They can be either sparse or dense, and * cdef _add_ -- add two matrices with identical parents * _matrix_times_matrix_c_impl -- multiply two matrices with compatible dimensions and identical base rings (both sparse or both dense) - * cdef _cmp_c_impl -- compare two matrices with identical parents + * cpdef _cmp_ -- compare two matrices with identical parents * cdef _lmul_c_impl -- multiply this matrix on the right by a scalar, i.e., self * scalar * cdef _rmul_c_impl -- multiply this matrix on the left by a scalar, i.e., scalar * self * __copy__ diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 93ca04b06ad..75201aaeab8 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -5260,7 +5260,7 @@ cdef class Matrix(sage.structure.element.Matrix): cdef long _hash(self) except -1: raise NotImplementedError - cdef int _cmp_c_impl(left,Element right) except -2: + cpdef int _cmp_(left,Element right) except -2: """ Compare two matrices. diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index 7b8e6d88134..268d64ffc0c 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -458,7 +458,7 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): # x * cdef _sub_ # * cdef _mul_ # x * cdef _lmul_ -- scalar multiplication - # x * cdef _cmp_c_impl + # x * cpdef _cmp_ # x * __neg__ # * __invert__ # x * __copy__ @@ -725,7 +725,7 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): else: raise TypeError, "mutable matrices are unhashable" - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: """ Implements comparison of two cyclotomic matrices with identical parents. @@ -749,7 +749,7 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): sage: cmp(2*A,A) 1 """ - return self._matrix._cmp_c_impl((right)._matrix) + return self._matrix._cmp_((right)._matrix) def __copy__(self): """ diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 77db32dceb2..b91da7d27e8 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -102,7 +102,7 @@ cdef class Matrix_dense(matrix.Matrix): else: raise RuntimeError, "unknown matrix version (=%s)"%version - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: """ EXAMPLES:: diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 4f7746b1562..3a1f1eed83d 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -386,7 +386,7 @@ cdef class Matrix_double_dense(matrix_dense.Matrix_dense): return M - # * cdef _cmp_c_impl + # * cpdef _cmp_ # x * __copy__ # * _list -- list of underlying elements (need not be a copy) # * _dict -- sparse dictionary of underlying elements (need not be a copy) diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index ba52b0708d1..14b0d8b8d03 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -184,7 +184,7 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): # LEVEL 2 functionality # * cdef _add_ # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * __neg__ # * __invert__ # x * __copy__ diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index a9d1c96c367..f406656082b 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -323,7 +323,7 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): # LEVEL 2 functionality # x * cdef _add_ # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * __neg__ # * __invert__ # x * __copy__ diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index a04fe5f7a66..bb0ffd45b38 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -711,7 +711,7 @@ cdef class Matrix_integer_dense(matrix_dense.Matrix_dense): # dense or sparse # x * cdef _add_ # x * cdef _sub_ # x * cdef _mul_ - # x * cdef _cmp_c_impl + # x * cpdef _cmp_ # x * __neg__ # x * __invert__ -> SEE LEVEL 3 FUNCTIONALITIES # x * __copy__ @@ -1082,7 +1082,7 @@ cdef class Matrix_integer_dense(matrix_dense.Matrix_dense): # dense or sparse return M - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: r""" Compares self with right, examining entries in lexicographic (row major) ordering. diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index 28efdb9eaaf..916bcf5163f 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -168,7 +168,7 @@ cdef class Matrix_integer_sparse(matrix_sparse.Matrix_sparse): # * cdef _add_ # * cdef _sub_ # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * __neg__ # * __invert__ # * __copy__ @@ -181,7 +181,7 @@ cdef class Matrix_integer_sparse(matrix_sparse.Matrix_sparse): # def _unpickle(self, data, int version): # use version >= 0 # cpdef ModuleElement _add_(self, ModuleElement right): # cdef _mul_(self, Matrix right): - # cdef int _cmp_c_impl(self, Matrix right) except -2: + # cpdef int _cmp_(self, Matrix right) except -2: # def __neg__(self): # def __invert__(self): # def __copy__(self): diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 642128eac3d..e14177b2776 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -588,7 +588,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse # * def _pickle # * def _unpickle # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * _list -- list of underlying elements (need not be a copy) # * _dict -- sparse dictionary of underlying elements (need not be a copy) ######################################################################## @@ -1498,7 +1498,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse A.subdivide(*self.subdivisions()) return A - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: if self._nrows == 0 or self._ncols == 0: return 0 return mzd_cmp(self._entries, (right)._entries) diff --git a/src/sage/matrix/matrix_mod2e_dense.pyx b/src/sage/matrix/matrix_mod2e_dense.pyx index 5ef7623937b..ffd5d4d7889 100644 --- a/src/sage/matrix/matrix_mod2e_dense.pyx +++ b/src/sage/matrix/matrix_mod2e_dense.pyx @@ -698,7 +698,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): """ return self._richcmp(right, op) - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: if self._nrows == 0 or self._ncols == 0: return 0 return mzed_cmp(self._entries, (right)._entries) diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 61a5d32b854..a377b936cea 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -950,7 +950,7 @@ cdef class Matrix_modn_dense_template(matrix_dense.Matrix_dense): return M - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: r""" Compare two dense matrices over `\Z/n\Z` diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index be1cee5ccb3..c36daac089a 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -247,7 +247,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): # * def _unpickle # * cdef _add_ # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * __neg__ # * __invert__ # * __copy__ @@ -259,7 +259,7 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): # def _unpickle(self, data, int version): # use version >= 0 # cpdef ModuleElement _add_(self, ModuleElement right): # cdef _mul_(self, Matrix right): - # cdef int _cmp_c_impl(self, Matrix right) except -2: + # cpdef int _cmp_(self, Matrix right) except -2: # def __neg__(self): # def __invert__(self): # def __copy__(self): diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index a71f8842045..94959dcb0f8 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -315,7 +315,7 @@ cdef class Matrix_rational_dense(matrix_dense.Matrix_dense): # x * cdef _add_ # x * cdef _mul_ # x * cdef _vector_times_matrix_ - # x * cdef _cmp_c_impl + # x * cpdef _cmp_ # x * __neg__ # * __invert__ # x * __copy__ @@ -410,7 +410,7 @@ cdef class Matrix_rational_dense(matrix_dense.Matrix_dense): sig_off() return M - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: cdef mpq_t *a cdef mpq_t *b cdef Py_ssize_t i, j @@ -589,7 +589,7 @@ cdef class Matrix_rational_dense(matrix_dense.Matrix_dense): return M # cdef _mul_(self, Matrix right): - # cdef int _cmp_c_impl(self, Matrix right) except -2: + # cpdef int _cmp_(self, Matrix right) except -2: # def __invert__(self): # def _list(self): # def _dict(self): diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 225eea012f6..64c70ac9ef6 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -172,7 +172,7 @@ cdef class Matrix_rational_sparse(matrix_sparse.Matrix_sparse): # * cdef _add_ # * cdef _sub_ # * cdef _mul_ - # * cdef _cmp_c_impl + # * cpdef _cmp_ # * __neg__ # * __invert__ # * __copy__ @@ -280,7 +280,7 @@ cdef class Matrix_rational_sparse(matrix_sparse.Matrix_sparse): # def _unpickle(self, data, int version): # use version >= 0 # cpdef ModuleElement _add_(self, ModuleElement right): # cdef _mul_(self, Matrix right): - # cdef int _cmp_c_impl(self, Matrix right) except -2: + # cpdef int _cmp_(self, Matrix right) except -2: # def __neg__(self): # def __invert__(self): # def __copy__(self): diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 4ebbf92b347..8ed13043fae 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -358,7 +358,7 @@ cdef class Matrix_sparse(matrix.Matrix): else: raise RuntimeError, "unknown matrix version (=%s)"%version - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: return cmp(self._dict(), right._dict()) def transpose(self): diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index a9faca6518c..2951c1a4847 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -214,7 +214,7 @@ hardly by used. ....: " return (left)._cmp(right)", ....: " def __richcmp__(left, right, op):", ....: " return (left)._richcmp(right,op)", - ....: " cdef int _cmp_c_impl(left, Element right) except -2:", + ....: " cpdef int _cmp_(left, Element right) except -2:", ....: " return cmp(left.x,right.x)", ....: " def raw_test(self):", ....: " return -self", @@ -233,7 +233,7 @@ hardly by used. ....: " return (left)._cmp(right)", ....: " def __richcmp__(left, right, op):", ....: " return (left)._richcmp(right,op)", - ....: " cdef int _cmp_c_impl(left, Element right) except -2:", + ....: " cpdef int _cmp_(left, Element right) except -2:", ....: " return cmp(left.x,right.x)", ....: " def raw_test(self):", ....: " return -self", diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 20ee29fa6e9..78fa74f27d9 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -169,7 +169,7 @@ cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element right_r) except -2: + cpdef int _cmp_(self, Element right_r) except -2: """ Compare self to right, where right is guaranteed to have the same parent as self. diff --git a/src/sage/modules/fg_pid/fgp_morphism.py b/src/sage/modules/fg_pid/fgp_morphism.py index 471797e1f28..436c01726f1 100644 --- a/src/sage/modules/fg_pid/fgp_morphism.py +++ b/src/sage/modules/fg_pid/fgp_morphism.py @@ -149,7 +149,7 @@ def im_gens(self): self.__im_gens = tuple([self(x) for x in self.domain().gens()]) return self.__im_gens - def __cmp__(self, right): + def _cmp_(self, right): """ EXAMPLES:: @@ -173,14 +173,14 @@ def __cmp__(self, right): sage: phi == psi True """ - if not isinstance(right, FGP_Morphism): - raise TypeError a = (self.domain(), self.codomain()) b = (right.domain(), right.codomain()) c = cmp(a,b) if c: return c return cmp(self.im_gens(), right.im_gens()) + __cmp__ = _cmp_ + def __add__(self, right): """ EXAMPLES:: diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 43d69f29bed..fb1a0561d96 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -1668,7 +1668,7 @@ cdef class FreeModuleElement(Vector): # abstract base class s = sum([a**p for a in abs_self]) return s**(__one__/p) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES:: @@ -4532,7 +4532,7 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): v[i] = prod return left._new_c(v) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Compare two sparse free module elements. diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index ec04772f1c5..78de0a680fa 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -95,7 +95,7 @@ def __init__(self, parent): raise TypeError("parent must be a Hom space") sage.categories.morphism.Morphism.__init__(self, parent) - def __cmp__(self, other): + def _cmp_(self, other): """ Compare two matrix morphisms. @@ -109,6 +109,8 @@ def __cmp__(self, other): """ return cmp(self.matrix(), other.matrix()) + __cmp__ = _cmp_ + def _call_(self, x): """ Evaluate this matrix morphism at an element of the domain. diff --git a/src/sage/modules/vector_integer_dense.pyx b/src/sage/modules/vector_integer_dense.pyx index ff6b12bfcb1..562bc37fd48 100644 --- a/src/sage/modules/vector_integer_dense.pyx +++ b/src/sage/modules/vector_integer_dense.pyx @@ -121,7 +121,7 @@ cdef class Vector_integer_dense(free_module_element.FreeModuleElement): mpz_clear(self._entries[i]) sage_free(self._entries) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES:: diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index b5dc41a898c..d0ce7e4ab6a 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -185,7 +185,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): if self._entries: mzd_free(self._entries) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES:: sage: v = vector(GF(2), [0,0,0,0]) diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index 29d9dd3e0b4..12e013cfdf3 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -166,7 +166,7 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): if self._entries: sage_free(self._entries) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES: sage: v = vector(GF(5), [0,0,0,0]) diff --git a/src/sage/modules/vector_rational_dense.pyx b/src/sage/modules/vector_rational_dense.pyx index ad1dea2eee2..8d1918e5023 100644 --- a/src/sage/modules/vector_rational_dense.pyx +++ b/src/sage/modules/vector_rational_dense.pyx @@ -146,7 +146,7 @@ cdef class Vector_rational_dense(free_module_element.FreeModuleElement): mpq_clear(self._entries[i]) sage_free(self._entries) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES:: diff --git a/src/sage/numerical/linear_functions.pxd b/src/sage/numerical/linear_functions.pxd index 9b96ab6a5c4..822b516ac29 100644 --- a/src/sage/numerical/linear_functions.pxd +++ b/src/sage/numerical/linear_functions.pxd @@ -18,10 +18,8 @@ cdef class LinearFunction(ModuleElement): cpdef ModuleElement _rmul_(self, RingElement b) cpdef ModuleElement _neg_(self) cpdef _acted_upon_(self, x, bint self_on_left) - cdef _richcmp(left, right, int op) cpdef is_zero(self) cpdef equals(LinearFunction left, LinearFunction right) - cdef int _cmp_c_impl(left, Element right) except -2 cdef class LinearConstraintsParent_class(Parent): cdef LinearFunctionsParent_class _LF @@ -31,7 +29,6 @@ cdef class LinearConstraintsParent_class(Parent): cdef class LinearConstraint(Element): cdef bint equality cdef list constraints - cdef _richcmp(left, right, int op) cdef LinearConstraint _chained_comparator_hack_part1(LinearConstraint left, LinearConstraint right) cdef _chained_comparator_hack_part2(self) cpdef equals(LinearConstraint left, LinearConstraint right) diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index ec7e86743f0..1ec358dc8d7 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -848,11 +848,6 @@ cdef class LinearFunction(ModuleElement): """ Override the rich comparison. - The Sage framework sometimes expects that rich comparison - results in a boolean value, but we want to return - :class:`~sage.numerical.linear_functions.LinearConstraint` - objects. - EXAMPLES:: sage: p = MixedIntegerLinearProgram() @@ -946,7 +941,7 @@ cdef class LinearFunction(ModuleElement): sage: d = {} sage: d[f] = 3 """ - # see _cmp_c_impl() if you want to change the hash function + # see _cmp_() if you want to change the hash function return id(self) % LONG_MAX def __cmp__(left, right): @@ -962,7 +957,7 @@ cdef class LinearFunction(ModuleElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Implement comparison of two linear functions. @@ -1510,11 +1505,6 @@ cdef class LinearConstraint(Element): """ Override the rich comparison. - The Sage framework sometimes expects that rich comparison - results in a boolean value, but we want to return - :class:`~sage.numerical.linear_functions.LinearConstraint` - objects. - EXAMPLES:: sage: p = MixedIntegerLinearProgram() diff --git a/src/sage/numerical/linear_tensor_element.pxd b/src/sage/numerical/linear_tensor_element.pxd index d693295e5b9..5de33004079 100644 --- a/src/sage/numerical/linear_tensor_element.pxd +++ b/src/sage/numerical/linear_tensor_element.pxd @@ -1,14 +1,4 @@ -from sage.structure.element cimport Element, ModuleElement, RingElement - +from sage.structure.element cimport Element, ModuleElement cdef class LinearTensor(ModuleElement): cpdef dict _f - cpdef ModuleElement _add_(self, ModuleElement b) - cpdef ModuleElement _sub_(self, ModuleElement b) - cpdef ModuleElement _neg_(self) - cpdef ModuleElement _lmul_(self, RingElement b) - cpdef ModuleElement _rmul_(self, RingElement b) - cdef _richcmp(left, right, int op) - cdef int _cmp_c_impl(left, Element right) except -2 - - diff --git a/src/sage/numerical/linear_tensor_element.pyx b/src/sage/numerical/linear_tensor_element.pyx index 313c5a0de67..85690475c82 100644 --- a/src/sage/numerical/linear_tensor_element.pyx +++ b/src/sage/numerical/linear_tensor_element.pyx @@ -361,11 +361,6 @@ cdef class LinearTensor(ModuleElement): """ Override the rich comparison. - The Sage framework sometimes expects that rich comparison - results in a boolean value, but we want to return - :class:`~sage.numerical.linear_functions.LinearConstraint` - objects. - EXAMPLES:: sage: mip. = MixedIntegerLinearProgram() @@ -464,7 +459,7 @@ cdef class LinearTensor(ModuleElement): sage: d = {} sage: d[f] = 3 """ - # see _cmp_c_impl() if you want to change the hash function + # see _cmp_() if you want to change the hash function return id(self) % LONG_MAX def __cmp__(left, right): @@ -480,7 +475,7 @@ cdef class LinearTensor(ModuleElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Implement comparison of two linear functions. diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 5a735e7320e..b97371a4cae 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -182,11 +182,7 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): sage: cmp(CDF, CDF) 0 """ - return (left)._richcmp_helper(right, op) - - cdef int _cmp_c_impl(left, Parent right) except -2: - # There is only one CDF. - return cmp(type(left),type(right)) + return (left)._richcmp(right, op) def __hash__(self): """ @@ -263,7 +259,7 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): """ return r"\Bold{C}" - def _cmp_(self, x): + cpdef int _cmp_(self, x) except -2: """ Compare ``x`` to ``self``. @@ -802,7 +798,7 @@ cdef class ComplexDoubleElement(FieldElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ We order the complex numbers in dictionary order by real parts then imaginary parts. diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index eae980bdb87..9610ee36528 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -1036,7 +1036,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): cdef ComplexIntervalFieldElement lt, rt lt = left rt = right @@ -1094,7 +1094,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): return (left)._cmp(right) - cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2: + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: """ Intervals are compared lexicographically on the 4-tuple: ``(x.real().lower(), x.real().upper(), diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index 822a32e8236..b1e6e524fc6 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -1138,7 +1138,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2: + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: cdef int a, b a = mpfr_nan_p(left.__re) b = mpfr_nan_p((right).__re) diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 615c877b6c3..0073e2afb76 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -1383,7 +1383,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Comparison of finite field elements is correct or equality tests and somewhat random for ``<`` and ``>`` type of diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index 8890fe78be9..c62b501b5fd 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -905,7 +905,7 @@ cdef class FiniteField_ntl_gf2eElement(FinitePolyExtElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Comparison of finite field elements. """ diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 5b9ec573a80..11693190a5e 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -382,7 +382,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): x.construct(self.val) return x - cdef int _cmp_c_impl(FiniteFieldElement_pari_ffelt self, Element other) except -2: + cpdef int _cmp_(FiniteFieldElement_pari_ffelt self, Element other) except -2: """ Comparison of finite field elements. diff --git a/src/sage/rings/finite_rings/hom_finite_field.pxd b/src/sage/rings/finite_rings/hom_finite_field.pxd index 6f2351a4686..5627641fcf6 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pxd +++ b/src/sage/rings/finite_rings/hom_finite_field.pxd @@ -20,5 +20,3 @@ cdef class FrobeniusEndomorphism_finite_field(FrobeniusEndomorphism_generic): cdef long _order cpdef Element _call_(self, x) - - cdef int _cmp_c_impl(self, Element other) except -2 diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 12d09d7034b..4c01d8e2b5e 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1821,7 +1821,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): mpz_fdiv_q_2exp(x.value, self.value, -k) return x - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLES:: @@ -2271,7 +2271,7 @@ cdef class IntegerMod_int(IntegerMod_abstract): - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: """ EXAMPLES:: @@ -3143,7 +3143,7 @@ cdef class IntegerMod_int64(IntegerMod_abstract): return self.ivalue - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: """ EXAMPLES:: diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 9e19a8b8679..e6a632219d7 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -353,7 +353,7 @@ cdef class FpTElement(RingElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ Compares this with another element. The ordering is arbitrary, but it is an ordering, and it is consistent between runs. It has diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index b55bf42dc07..381e11ad6c4 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -852,7 +852,7 @@ cdef class FractionFieldElement(FieldElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index 1cbeb7460e1..c701e7f8e39 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -361,7 +361,7 @@ cdef class FunctionFieldElement_polymod(FunctionFieldElement): """ return not not self._x - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: @@ -563,7 +563,7 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): """ return not not self._x - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ EXAMPLES:: diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index d8fc13805e6..299878d2edc 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -893,7 +893,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return (left)._richcmp(right, op) return (left)._rich_to_bool(op, c) - cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2: + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: cdef int i i = mpz_cmp((left).value, (right).value) if i < 0: return -1 diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index c88b6b34948..80a0faffe12 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -359,9 +359,9 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: cmp(ZZ,QQ) -1 """ - return (left)._richcmp_helper(right, op) + return (left)._richcmp(right, op) - def _cmp_(left, right): + cpdef int _cmp_(left, right) except -2: """ Compare ``left`` and ``right``. @@ -373,7 +373,6 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: IntegerRing_class._cmp_(ZZ,QQ) -1 """ - if isinstance(right,IntegerRing_class): return 0 if isinstance(right, sage.rings.rational_field.RationalField): diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index f00b3f214a9..68f5216569d 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -910,7 +910,7 @@ cdef class LaurentSeries(AlgebraElement): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element right_r) except -2: + cpdef int _cmp_(self, Element right_r) except -2: r""" Comparison of self and right. diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 024132dd24d..61729cde43e 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1152,7 +1152,7 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: r""" EXAMPLES: @@ -1458,7 +1458,7 @@ cdef class RingHomomorphism_from_base(RingHomomorphism): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: r""" EXAMPLES: @@ -2113,7 +2113,7 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: if left is right: return 0 domain = left.domain() c = cmp(domain, right.domain()) diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index ca49d4d7960..a233bcfef2a 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -208,7 +208,7 @@ class MPowerSeries(PowerSeries): # # change_ring : works just fine # - # _cmp_c_impl : don't understand this + # _cmp_ : don't understand this # # __copy__ : works just fine # @@ -659,7 +659,7 @@ def __invert__(self): raise NotImplementedError("Multiplicative inverse of multivariate power series currently implemented only if constant coefficient is a unit.") ## comparisons - def __cmp__(self, other): + def _cmp_(self, other): """ Compare ``self`` to ``other``. diff --git a/src/sage/rings/number_field/morphism.py b/src/sage/rings/number_field/morphism.py index 2bb784b4d67..b4f3900fe67 100644 --- a/src/sage/rings/number_field/morphism.py +++ b/src/sage/rings/number_field/morphism.py @@ -612,7 +612,7 @@ def im_gens(self): self.__im_gens = v return v - def __cmp__(self, other): + def _cmp_(self, other): """ Compare @@ -623,10 +623,10 @@ def __cmp__(self, other): sage: all([u^2 == e, u*v == w, u != e]) True """ - if not isinstance(other, RelativeNumberFieldHomomorphism_from_abs): - return cmp(type(self), type(other)) return cmp(self.abs_hom(), other.abs_hom()) + __cmp__ = _cmp_ + def _repr_defn(self): r""" Return a string describing the images of the generators under this map. diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index c051e7d438a..9f00e820853 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -777,7 +777,7 @@ cdef class NumberFieldElement(FieldElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2: + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: cdef NumberFieldElement _right = right return not (ZZX_equal(left.__numerator, _right.__numerator) and ZZ_equal(left.__denominator, _right.__denominator)) diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index a5ba2d3132e..98635c2da43 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -686,7 +686,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element _right, int op): + cpdef _richcmp_(left, Element _right, int op): r""" C implementation of comparison. @@ -886,7 +886,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element _right) except -2: + cpdef int _cmp_(left, Element _right) except -2: """ C implementation of comparison. """ diff --git a/src/sage/rings/padics/morphism.pxd b/src/sage/rings/padics/morphism.pxd index 414ba9e80ed..acb6ebb98d5 100644 --- a/src/sage/rings/padics/morphism.pxd +++ b/src/sage/rings/padics/morphism.pxd @@ -8,6 +8,3 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): cdef long _order cpdef Element _call_(self,x) - - cdef int _cmp_c_impl(self, Element other) except -2 - diff --git a/src/sage/rings/padics/morphism.pyx b/src/sage/rings/padics/morphism.pyx index 7eb2d2549b9..f9eb16d3cc5 100644 --- a/src/sage/rings/padics/morphism.pyx +++ b/src/sage/rings/padics/morphism.pyx @@ -289,7 +289,7 @@ cdef class FrobeniusEndomorphism_padics(RingHomomorphism): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Compare left and right """ diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index d910ba73d41..d8013cc2310 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -464,7 +464,7 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ First compare valuations, then compare the values. diff --git a/src/sage/rings/padics/padic_generic_element.pxd b/src/sage/rings/padics/padic_generic_element.pxd index 65ae47f2281..2707022c7ed 100644 --- a/src/sage/rings/padics/padic_generic_element.pxd +++ b/src/sage/rings/padics/padic_generic_element.pxd @@ -8,7 +8,6 @@ from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational cdef class pAdicGenericElement(LocalGenericElement): - cdef int _cmp_c_impl(left, Element right) except -2 cdef long valuation_c(self) cpdef val_unit(self) diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 352f37f0e73..2e9d8b84d66 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -55,7 +55,7 @@ cdef class pAdicGenericElement(LocalGenericElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ First compare valuations, then compare normalized residue of unit part. diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index e64ee68990f..23f593849c0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -911,7 +911,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial_generic): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(self, Element right_r) except -2: + cpdef int _cmp_(self, Element right_r) except -2: r""" Comparison of ``self`` and ``right_r``. @@ -2034,7 +2034,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial_generic): ans._poly = self._poly.__floordiv__((right)._poly) return ans - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 11239961c9f..4d8d9e60905 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -1399,32 +1399,19 @@ def lt(self): return self.__lt def __eq__(self,right): - """ - - """ - if not isinstance(right,MPolynomial_polydict): + if not isinstance(right, MPolynomial_polydict): # we want comparison with zero to be fast - if right == 0: - if self._MPolynomial_element__element.dict()=={}: - return True - else: - return False - return self._richcmp_(right,2) + if not right: + return not self._MPolynomial_element__element.dict() + return CommutativeRingElement.__eq__(self, right) return self._MPolynomial_element__element == right._MPolynomial_element__element def __ne__(self,right): - """ - - """ - if not isinstance(right,MPolynomial_polydict): + if not isinstance(right, MPolynomial_polydict): # we want comparison with zero to be fast - if right == 0: - if self._MPolynomial_element__element.dict()=={}: - return False - else: - return True - # maybe add constant elements as well - return self._richcmp_(right,3) + if not right: + return not not self._MPolynomial_element__element.dict() + return CommutativeRingElement.__ne__(self, right) return self._MPolynomial_element__element != right._MPolynomial_element__element def __nonzero__(self): diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd b/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd index 747b33a67a6..57e4817a546 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pxd @@ -2,7 +2,6 @@ from sage.libs.singular.decl cimport poly, ring from sage.rings.polynomial.multi_polynomial cimport MPolynomial from sage.rings.polynomial.multi_polynomial_ring_generic cimport MPolynomialRing_generic -from sage.structure.parent cimport Parent cdef class MPolynomialRing_libsingular @@ -21,10 +20,6 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): cdef object __minpoly cdef poly *_one_element_poly cdef ring *_ring - cdef int _cmp_c_impl(left, Parent right) except -2 - - #cpdef MPolynomial_libsingular _element_constructor_(self, element) # new polynomials - cdef MPolynomial_libsingular new_MP(MPolynomialRing_libsingular parent, poly *p) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index b0d4d9a2108..ec9fa4039ea 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -1456,9 +1456,9 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_generic): sage: P == R False """ - return (left)._richcmp_helper(right, op) + return (left)._richcmp(right, op) - def _cmp_(left, right): + cpdef int _cmp_(left, right) except -2: """ Compare ``left`` with ``right``. @@ -2200,7 +2200,7 @@ cdef class MPolynomial_libsingular(sage.rings.polynomial.multi_polynomial.MPolyn """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: if left is right: return 0 cdef poly *p = (left)._poly diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pxd b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pxd index bb998249443..426e5f8b2bf 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pxd @@ -1,6 +1,4 @@ -import sage.rings.ring cimport sage.rings.ring - from sage.structure.parent cimport Parent cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing): @@ -11,4 +9,3 @@ cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing): cdef public dict _magma_cache cdef _coerce_c_impl(self, x) - cdef int _cmp_c_impl(left, Parent right) except -2 diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx index cf01c7f42c8..a35253ed3be 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx @@ -334,7 +334,7 @@ cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing): def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Parent right) except -2: + cpdef int _cmp_(left, right) except -2: if not is_MPolynomialRing(right): return cmp(type(left),type(right)) else: diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 4293146465a..c4995df1f85 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -2265,7 +2265,7 @@ cdef class BooleanMonomial(MonoidElement): # boilerplate code from sage.structure.parent return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: cdef int res res = left._pbmonom.compare((right)._pbmonom) return res @@ -3141,7 +3141,7 @@ cdef class BooleanPolynomial(MPolynomial): #boilerplate from sage.structure.element return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: diff --git a/src/sage/rings/polynomial/plural.pxd b/src/sage/rings/polynomial/plural.pxd index af60cd68c2a..6b58253cb3c 100644 --- a/src/sage/rings/polynomial/plural.pxd +++ b/src/sage/rings/polynomial/plural.pxd @@ -16,8 +16,6 @@ cdef class NCPolynomialRing_plural(Ring): cdef object __term_order cdef public object _has_singular cdef public object _magma_gens, _magma_cache -# cdef _richcmp_c_impl(left, Parent right, int op) - cdef int _cmp_c_impl(left, Parent right) except -2 cdef ring *_ring # cdef NCPolynomial_plural _one_element diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 67659c49ecb..5983834ef69 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -1473,7 +1473,7 @@ cdef class NCPolynomial_plural(RingElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: if left is right: return 0 cdef poly *p = (left)._poly diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 9b0c7b368a5..732c2a28bb6 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -787,7 +787,7 @@ cdef class Polynomial(CommutativeAlgebraElement): expr *= x return expr - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ Compare the two polynomials self and other. diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 78a212d43ea..d4777f3e885 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -543,7 +543,7 @@ cdef class Polynomial_template(Polynomial): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ EXAMPLE:: diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index 2d8af8af80e..567f9211b7b 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -384,7 +384,7 @@ cdef class Polynomial_ZZ_pEX(Polynomial_template): raise ValueError("unknown algorithm") return res != 0 - cdef int _cmp_c_impl(left,Element right) except -2: + cpdef int _cmp_(left,Element right) except -2: """ EXAMPLE:: diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 41a91080cb2..0e742ddf94f 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -327,7 +327,7 @@ cdef class PowerSeries(AlgebraElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(self, Element right) except -2: + cpdef int _cmp_(self, Element right) except -2: r""" Comparison of self and ``right``. diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index b7c38e071fd..db85a387de8 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -709,7 +709,7 @@ cdef class Rational(sage.structure.element.FieldElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, sage.structure.element.Element right) except -2: + cpdef int _cmp_(left, sage.structure.element.Element right) except -2: cdef int i i = mpq_cmp((left).value, (right).value) if i < 0: return -1 diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 36a93ad475e..f9f6cd1c822 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -1419,7 +1419,7 @@ cdef class RealBall(RingElement): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right``. diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index cb69ac4c4aa..dfe37dcf998 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -1680,7 +1680,7 @@ cdef class RealDoubleElement(FieldElement): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): # We really need to use the correct operators, to deal # correctly with NaNs. cdef double x = (left)._value diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 0d77212d83a..fd893dc2b87 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -631,7 +631,7 @@ cdef class LazyFieldElement(FieldElement): """ return self._new_unop(self, inv) - cdef int _cmp_c_impl(self, Element other) except -2: + cpdef int _cmp_(self, Element other) except -2: """ If things are being wrapped, tries to compare values. That failing, it tries to compare intervals, which may return a false negative. diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 24a1bac50b9..1f530800c6d 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -3289,7 +3289,7 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Implements comparisons between intervals. (See the file header comment for more information on interval comparison.) @@ -3513,7 +3513,7 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Implements the lexicographic total order on intervals. """ diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 279af4aeabc..b78086c611a 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -3810,7 +3810,7 @@ cdef class RealNumber(sage.structure.element.RingElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Return ``-1`` if exactly one of the numbers is ``NaN``. Return ``-1`` if ``left`` is less than ``right``, ``0`` if ``left`` and ``right`` diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index 6a7199fa8ac..cc4d1104ab8 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -173,7 +173,7 @@ cdef class TropicalSemiringElement(RingElement): """ return (left)._richcmp(right, op) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Return ``-1`` if ``left`` is less than ``right``, ``0`` if ``left`` and ``right`` are equal, and ``1`` if ``left`` is diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 027feca7301..f627e33b8f0 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1234,8 +1234,7 @@ def __hash__(self): return self.__this_hash - - def __cmp__(self, other): + def _cmp_(self, other): r""" Function that implements comparisons between isogeny objects. @@ -1265,14 +1264,11 @@ def __cmp__(self, other): sage: phi.dual() == psi.dual() True """ - if (not isinstance(other, EllipticCurveIsogeny)): - return -1 - if (self.__kernel_polynomial is None): self.__init_kernel_polynomial() # We cannot just compare kernel polynomials, as was done until - # :trac:`11327`, as then phi and -phi compare equal, and + # Trac #11327, as then phi and -phi compare equal, and # similarly with phi and any composition of phi with an # automorphism of its codomain, or any post-isomorphism. # Comparing domains, codomains and rational maps seems much @@ -1282,7 +1278,9 @@ def __cmp__(self, other): if t: return t t = cmp(self.codomain(), other.codomain()) if t: return t - return cmp(self.rational_maps(), other.rational_maps()) + return cmp(self.rational_maps(), other.rational_maps()) + + __cmp__ = _cmp_ def __neg__(self): r""" diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 830f21345b6..015de65050e 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -95,9 +95,8 @@ def __cmp__(self, other): sage: baseWI(1,2,3,4)>baseWI(1,2,3,4) False - :: + It will never return equality if other is of another type:: - It will never return equality if other is of another type: sage: baseWI() == 1 False @@ -368,7 +367,7 @@ def isomorphisms(E,F,JustOne=False): ans.sort() return ans -class WeierstrassIsomorphism(baseWI,Morphism): +class WeierstrassIsomorphism(baseWI, Morphism): r""" Class representing a Weierstrass isomorphism between two elliptic curves. """ @@ -470,44 +469,44 @@ def __init__(self, E=None, urst=None, F=None): self._codomain_curve = F return - def __cmp__(self, other): + def _cmp_(self, other): r""" Standard comparison function for the WeierstrassIsomorphism class. - EXAMPLE:: + EXAMPLES:: - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * - sage: E=EllipticCurve('389a1') - sage: F=E.change_weierstrass_model(1,2,3,4) - sage: w1=E.isomorphism_to(F) - sage: w1==w1 - True - sage: w2 = F.automorphisms()[0] *w1 - sage: w1==w2 - False - - :: - - sage: E=EllipticCurve_from_j(GF(7)(0)) - sage: F=E.change_weierstrass_model(2,3,4,5) - sage: a=E.isomorphisms(F) - sage: b=[w*a[0] for w in F.automorphisms()] - sage: b.sort() - sage: a==b - True - sage: c=[a[0]*w for w in E.automorphisms()] - sage: c.sort() - sage: a==c - True + sage: from sage.schemes.elliptic_curves.weierstrass_morphism import * + sage: E=EllipticCurve('389a1') + sage: F=E.change_weierstrass_model(1,2,3,4) + sage: w1=E.isomorphism_to(F) + sage: w1==w1 + True + sage: w2 = F.automorphisms()[0] *w1 + sage: w1==w2 + False + + :: + + sage: E=EllipticCurve_from_j(GF(7)(0)) + sage: F=E.change_weierstrass_model(2,3,4,5) + sage: a=E.isomorphisms(F) + sage: b=[w*a[0] for w in F.automorphisms()] + sage: b.sort() + sage: a==b + True + sage: c=[a[0]*w for w in E.automorphisms()] + sage: c.sort() + sage: a==c + True """ - if not isinstance(other, WeierstrassIsomorphism): - return cmp(type(self), type(other)) t = cmp(self._domain_curve, other._domain_curve) if t: return t t = cmp(self._codomain_curve, other._codomain_curve) if t: return t return baseWI.__cmp__(self,other) + __cmp__ = _cmp_ + def __call__(self, P): r""" Call function for WeierstrassIsomorphism class. diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 8de6aebe03e..5387b6d2eb2 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -1549,7 +1549,7 @@ def __len__(self): """ return len(self._coords) - def __cmp__(self, other): + def _cmp_(self, other): """ Compare two scheme morphisms. @@ -1579,6 +1579,8 @@ def __cmp__(self, other): return -1 return cmp(self._coords, other._coords) + __cmp__ = _cmp_ + def scheme(self): """ Return the scheme whose point is represented. diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 84f8a5b61ba..df28bfc7df0 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -876,7 +876,7 @@ def __init__(self, parent, fan_morphism, check=True): raise ValueError('The fan morphism codomain must be the fan of the codomain.') self._fan_morphism = fan_morphism - def __cmp__(self, right): + def _cmp_(self, right): r""" Compare ``self`` and ``right``. @@ -911,6 +911,8 @@ def __cmp__(self, right): else: return cmp(type(self), type(right)) + __cmp__ = _cmp_ + def _composition_(self, right, homset): """ Return the composition of ``self`` and ``right``. diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 34b0f5c7493..90607dfa6f2 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -34,10 +34,10 @@ cdef str arith_error_message(x, y, op) cdef class Element(SageObject): cdef Parent _parent - cdef _richcmp_c_impl(left, Element right, int op) - cdef int _cmp_c_impl(left, Element right) except -2 - cdef public _richcmp(self, right, int op) - cdef public _cmp(self, right) + cpdef _richcmp_(left, Element right, int op) + cpdef int _cmp_(left, Element right) except -2 + cdef _richcmp(self, right, int op) + cdef _cmp(self, right) cdef _set_parent_c(self, Parent parent) cpdef base_extend(self, R) cdef _rich_to_bool(self, int op, int r) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 316a5b52515..86649a62ef3 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -905,9 +905,6 @@ cdef class Element(SageObject): """ return not self - def _cmp_(left, right): - return left._cmp_c_impl(right) - cdef _cmp(left, right): """ Compare left and right. @@ -929,17 +926,9 @@ cdef class Element(SageObject): if r == 0: r = -1 return r - else: - if HAS_DICTIONARY(left): - left_cmp = left._cmp_ - if isinstance(left_cmp, MethodType): - # it must have been overridden - return left_cmp(right) - return left._cmp_c_impl(right) - - def _richcmp_(left, right, op): - return left._richcmp(right, op) + # Same parents + return left._cmp_(right) cdef _richcmp(left, right, int op): """ @@ -955,7 +944,7 @@ cdef class Element(SageObject): try: _left, _right = coercion_model.canonical_coercion(left, right) if isinstance(_left, Element): - return (_left)._richcmp_(_right, op) + return (_left)._richcmp(_right, op) return _rich_to_bool(op, cmp(_left, _right)) except (TypeError, NotImplementedError): r = cmp(type(left), type(right)) @@ -979,65 +968,54 @@ cdef class Element(SageObject): except TypeError: return _rich_to_bool(op, r) - if HAS_DICTIONARY(left): # fast check - left_cmp = left.__cmp__ - if isinstance(left_cmp, MethodType): - # it must have been overridden - return _rich_to_bool(op, left_cmp(right)) - - return left._richcmp_c_impl(right, op) + # Same parents + return left._richcmp_(right, op) cdef _rich_to_bool(self, int op, int r): return _rich_to_bool(op, r) #################################################################### - # For a derived Cython class, you **must** put the following in - # your subclasses, in order for it to take advantage of the - # above generic comparison code. You must also define - # either _cmp_c_impl (if your subclass is totally ordered), - # _richcmp_c_impl (if your subclass is partially ordered), or both - # (if your class has both a total order and a partial order; - # then the total order will be available with cmp(), and the partial - # order will be available with the relation operators; in this case - # you must also define __cmp__ in your subclass). - # This is simply how Python works. + # For a derived Cython class, you **must** put the __richcmp__ + # method below in your subclasses, in order for it to take + # advantage of the above generic comparison code. # - # For a *Python* class just define __cmp__ as always. - # But note that when this gets called you can assume that - # both inputs have identical parents. - # - # If your __cmp__ methods are not getting called, verify that the - # canonical_coercion(x,y) is not throwing errors. + # You must also define either _cmp_ (if your subclass is totally + # ordered), _richcmp_ (if your subclass is partially ordered), or + # both (if your class has both a total order and a partial order). + # If you want to use cmp(), then you must also define __cmp__ in + # your subclass. # + # In the _cmp_ and _richcmp_ methods, you can assume that both + # arguments have identical parents. #################################################################### def __richcmp__(left, right, int op): return (left)._richcmp(right, op) - #################################################################### - # If your subclass has both a partial order (available with the - # relation operators) and a total order (available with cmp()), - # you **must** put the following in your subclass. - # - # Note that in this case the total order defined by cmp() will - # not properly respect coercions. - #################################################################### def __cmp__(left, right): return (left)._cmp(right) - cdef _richcmp_c_impl(left, Element right, int op): - if (left)._richcmp_c_impl == Element._richcmp_c_impl and \ - (left)._cmp_c_impl == Element._cmp_c_impl: - # Not implemented, try some basic defaults - if op == Py_EQ: - return left is right - elif op == Py_NE: - return left is not right - return left._rich_to_bool(op, left._cmp_c_impl(right)) - - cdef int _cmp_c_impl(left, Element right) except -2: - ### For derived Cython code, you *MUST* ALSO COPY the __richcmp__ above - ### into your class!!! For Python code just use __cmp__. - raise NotImplementedError("BUG: sort algorithm for elements of '%s' not implemented"%right.parent()) + cpdef _richcmp_(left, Element right, int op): + # Obvious case + if left is right: + return _rich_to_bool(op, 0) + + cdef int c + try: + c = left._cmp_(right) + except NotImplementedError: + # Check equality by id(), knowing that left is not right + if op == Py_EQ: return False + if op == Py_NE: return True + raise + return _rich_to_bool(op, c) + + cpdef int _cmp_(left, Element right) except -2: + # Check for Python class defining __cmp__ + left_cmp = left.__cmp__ + if isinstance(left_cmp, MethodType): + return left_cmp(right) + raise NotImplementedError("comparison not implemented for %r"%type(left)) + cdef inline bint _rich_to_bool(int op, int r): if op == Py_LT: #< @@ -1124,7 +1102,7 @@ cdef class ElementWithCachedMethod(Element): ... " return (left)._cmp(right)", ... " def __richcmp__(left, right, op):", ... " return (left)._richcmp(right,op)", - ... " cdef int _cmp_c_impl(left, Element right) except -2:", + ... " cpdef int _cmp_(left, Element right) except -2:", ... " return cmp(left.x,right.x)", ... " def raw_test(self):", ... " return -self", @@ -1143,7 +1121,7 @@ cdef class ElementWithCachedMethod(Element): ... " return (left)._cmp(right)", ... " def __richcmp__(left, right, op):", ... " return (left)._richcmp(right,op)", - ... " cdef int _cmp_c_impl(left, Element right) except -2:", + ... " cpdef int _cmp_(left, Element right) except -2:", ... " return cmp(left.x,right.x)", ... " def raw_test(self):", ... " return -self", diff --git a/src/sage/structure/list_clone.pyx b/src/sage/structure/list_clone.pyx index 2a4b3d7ad27..f0d39e92fae 100644 --- a/src/sage/structure/list_clone.pyx +++ b/src/sage/structure/list_clone.pyx @@ -837,7 +837,7 @@ cdef class ClonableArray(ClonableElement): return (left)._richcmp(right, op) # See protocol in comment in sage/structure/element.pyx - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ TEST:: @@ -1593,7 +1593,7 @@ cdef class ClonableIntArray(ClonableElement): return (left)._richcmp(right, op) # See protocol in comment in sage/structure/element.pyx - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ TEST:: diff --git a/src/sage/structure/parent.pxd b/src/sage/structure/parent.pxd index 5104d448d03..29238003360 100644 --- a/src/sage/structure/parent.pxd +++ b/src/sage/structure/parent.pxd @@ -27,7 +27,8 @@ cdef class Parent(category_object.CategoryObject): cpdef register_conversion(self, mor) cpdef register_embedding(self, embedding) - cpdef bint _richcmp_helper(left, right, int op) except -2 + cpdef bint _richcmp(left, right, int op) except -2 + cpdef int _cmp_(left, right) except -2 cpdef bint is_exact(self) except -2 # Called from the __init__ method to set up coercion. diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 48a40986e7b..7c48d2f2bc4 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -94,6 +94,7 @@ This came up in some subtle bug once:: """ +from types import MethodType from element cimport parent_c cimport sage.categories.morphism as morphism cimport sage.categories.map as map @@ -183,7 +184,7 @@ def is_Parent(x): return isinstance(x, Parent) cdef bint guess_pass_parent(parent, element_constructor): - if isinstance(element_constructor, types.MethodType): + if isinstance(element_constructor, MethodType): return False elif isinstance(element_constructor, BuiltinMethodType): return element_constructor.__self__ is not parent @@ -1475,7 +1476,7 @@ cdef class Parent(category_object.CategoryObject): """ return True - cpdef bint _richcmp_helper(left, right, int op) except -2: + cpdef bint _richcmp(left, right, int op) except -2: """ Compare left and right. @@ -1497,10 +1498,7 @@ cdef class Parent(category_object.CategoryObject): else: # Both are parents -- but need *not* have the same type. - if HAS_DICTIONARY(left): - r = left.__cmp__(right) - else: - r = left._cmp_(right) + r = left._cmp_(right) if op == 0: #< return r < 0 @@ -1515,6 +1513,21 @@ cdef class Parent(category_object.CategoryObject): elif op == 5: #>= return r >= 0 + cpdef int _cmp_(left, right) except -2: + # Check for Python class defining __cmp__ + try: + return left.__cmp__(right) + except AttributeError: + pass + # Default: compare by id + if left is right: + return 0 + if (left) < (right): + return -1 + else: + return 1 + + # Should be moved and merged into the EnumeratedSets() category (#12955) def __len__(self): """ @@ -3099,7 +3112,7 @@ cdef class Set_PythonType_class(Set_generic): """ return -hash(self._type) - cpdef int _cmp_(self, other) except -100: + cpdef int _cmp_(self, other) except -2: """ Two Python type sets are considered the same if they contain the same type. diff --git a/src/sage/structure/parent_base.pyx b/src/sage/structure/parent_base.pyx index 0188f041553..1296cd5d4cb 100644 --- a/src/sage/structure/parent_base.pyx +++ b/src/sage/structure/parent_base.pyx @@ -63,11 +63,6 @@ cdef class ParentWithBase(parent_old.Parent): parent_old.Parent.__init__(self, coerce_from=coerce_from, actions=actions, embeddings=embeddings, category=category) self._base = base - def _richcmp(left, right, int op): - check_old_coerce(left) - return (left)._richcmp(right, op) # the cdef method - - cdef _coerce_c_impl(self,x): check_old_coerce(self) if not self._base is self: diff --git a/src/sage/structure/parent_old.pxd b/src/sage/structure/parent_old.pxd index 8980a41f3ed..f57e21a0665 100644 --- a/src/sage/structure/parent_old.pxd +++ b/src/sage/structure/parent_old.pxd @@ -33,12 +33,3 @@ cdef class Parent(parent.Parent): cdef _an_element_c_impl(self) cpdef _an_element_c(self) - - ################################################ - # Comparison of parent objects - cdef _richcmp(left, right, int op) - cdef int _cmp_c_impl(left, parent.Parent right) except -2 - - - - diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index 4b977ed1142..748a09b58bf 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -419,85 +419,6 @@ cdef class Parent(parent.Parent): list = parent.Parent._list_from_iterator_cached - ################################################ - # Comparison of parent objects - ################################################ - cdef _richcmp(left, right, int op): - """ - Compare left and right. - """ - check_old_coerce(left) - cdef int r - - if not isinstance(right, parent.Parent) or not isinstance(left, parent.Parent): - # One is not a parent -- use arbitrary ordering - if (left) < (right): - r = -1 - elif (left) > (right): - r = 1 - else: - r = 0 - - else: - # Both are parents -- but need *not* have the same type. - if HAS_DICTIONARY(left): - r = left.__cmp__(right) - else: - r = left._cmp_c_impl(right) - - if op == 0: #< - return PyBool_FromLong(r < 0) - elif op == 2: #== - return PyBool_FromLong(r == 0) - elif op == 4: #> - return PyBool_FromLong(r > 0) - elif op == 1: #<= - return PyBool_FromLong(r <= 0) - elif op == 3: #!= - return PyBool_FromLong(r != 0) - elif op == 5: #>= - return PyBool_FromLong(r >= 0) - -## #################################################################### -## # For a derived Cython class, you **must** put the following in -## # your subclasses, in order for it to take advantage of the -## # above generic comparison code. You must also define -## # _cmp_c_impl for a Cython class. -## # -## # For a derived Python class, simply define __cmp__. -## #################################################################### -## def __richcmp__(left, right, int op): -## return (left)._richcmp(right, op) - -## # NOT NEEDED, since all attributes are public! -## def __reduce__(self): -## if HAS_DICTIONARY(self): -## _dict = self.__dict__ -## else: -## _dict = None -## return (make_parent_v0, (self.__class__, _dict, self._has_coerce_map_from)) - - cdef int _cmp_c_impl(left, parent.Parent right) except -2: - check_old_coerce(left) - pass - # this would be nice to do, but we can't since - # it leads to infinite recursions -- and is slow -- and this - # stuff must be fast! - #if right.has_coerce_map_from(left): - # if left.has_coerce_map_from(right): - # return 0 - # else: - # return -1 - if (left) < (right): - return -1 - elif (left) > (right): - return 1 - return 0 - -## def __cmp__(left, right): -## return left._cmp_c_impl(right) # default - - ############################################################################ # Coercion Compatibility Layer ############################################################################ diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index da2f67dd443..1bc14e5c092 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1380,7 +1380,7 @@ cdef class Expression(CommutativeRingElement): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): cdef Expression l, r l = left @@ -3085,7 +3085,7 @@ cdef class Expression(CommutativeRingElement): """ return (left)._cmp(right) - cdef int _cmp_c_impl(left, Element right) except -2: + cpdef int _cmp_(left, Element right) except -2: """ Compare ``left`` and ``right``. From a10dcbaaaefb87d48cf337be367cd48f11ed6edf Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 16 Apr 2015 09:48:38 +0200 Subject: [PATCH 299/665] Use PyTypeObject from Cython --- build/pkgs/cython/package-version.txt | 2 +- build/pkgs/cython/patches/includes.patch | 283 +++++++++++++++++++++++ src/sage/ext/python_rich_object.pxi | 46 ---- src/sage/ext/pyx_visit.h | 11 + src/sage/ext/stdsage.pxd | 11 +- src/sage/libs/gmp/pylong.pxd | 2 - src/sage/misc/allocator.pxd | 5 +- src/sage/misc/allocator.pyx | 55 +---- src/sage/misc/classcall_metaclass.pxd | 4 +- src/sage/misc/classcall_metaclass.pyx | 42 +--- src/sage/misc/fast_methods.pyx | 1 - src/sage/misc/nested_class.pxd | 4 +- src/sage/misc/weak_dict.pyx | 4 +- src/sage/rings/integer.pyx | 22 +- src/sage/rings/real_double.pyx | 32 +-- src/sage/structure/coerce_dict.pyx | 83 +++---- 16 files changed, 379 insertions(+), 228 deletions(-) create mode 100644 build/pkgs/cython/patches/includes.patch delete mode 100644 src/sage/ext/python_rich_object.pxi create mode 100644 src/sage/ext/pyx_visit.h diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index 11eeebaa976..d8d72b412c0 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.22.p1 +0.22.p2 diff --git a/build/pkgs/cython/patches/includes.patch b/build/pkgs/cython/patches/includes.patch new file mode 100644 index 00000000000..3b915b61789 --- /dev/null +++ b/build/pkgs/cython/patches/includes.patch @@ -0,0 +1,283 @@ +Update Cython/Includes to upstream master + +diff --git a/Cython/Includes/cpython/bytes.pxd b/Cython/Includes/cpython/bytes.pxd +index 2fb3502..ea72c6a 100644 +--- a/Cython/Includes/cpython/bytes.pxd ++++ b/Cython/Includes/cpython/bytes.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + ctypedef struct va_list +diff --git a/Cython/Includes/cpython/cobject.pxd b/Cython/Includes/cpython/cobject.pxd +index 62c4706..497d8a9 100644 +--- a/Cython/Includes/cpython/cobject.pxd ++++ b/Cython/Includes/cpython/cobject.pxd +@@ -1,4 +1,3 @@ +-from cpython.ref cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/datetime.pxd b/Cython/Includes/cpython/datetime.pxd +index 3c6f8a7..2e0c4bd 100644 +--- a/Cython/Includes/cpython/datetime.pxd ++++ b/Cython/Includes/cpython/datetime.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + ctypedef struct PyTypeObject: +diff --git a/Cython/Includes/cpython/dict.pxd b/Cython/Includes/cpython/dict.pxd +index 69a416a..d58faea 100644 +--- a/Cython/Includes/cpython/dict.pxd ++++ b/Cython/Includes/cpython/dict.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/exc.pxd b/Cython/Includes/cpython/exc.pxd +index 89beb21..2e4eda5 100644 +--- a/Cython/Includes/cpython/exc.pxd ++++ b/Cython/Includes/cpython/exc.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/function.pxd b/Cython/Includes/cpython/function.pxd +index e8e4f06..0002a3f 100644 +--- a/Cython/Includes/cpython/function.pxd ++++ b/Cython/Includes/cpython/function.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/getargs.pxd b/Cython/Includes/cpython/getargs.pxd +index 591aefb..be6df32 100644 +--- a/Cython/Includes/cpython/getargs.pxd ++++ b/Cython/Includes/cpython/getargs.pxd +@@ -1,4 +1,3 @@ +-from cpython.ref cimport PyObject + + cdef extern from "Python.h": + ##################################################################### +diff --git a/Cython/Includes/cpython/list.pxd b/Cython/Includes/cpython/list.pxd +index 5cfd573..c6a2953 100644 +--- a/Cython/Includes/cpython/list.pxd ++++ b/Cython/Includes/cpython/list.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/method.pxd b/Cython/Includes/cpython/method.pxd +index bc09416..f51ebcc 100644 +--- a/Cython/Includes/cpython/method.pxd ++++ b/Cython/Includes/cpython/method.pxd +@@ -1,5 +1,6 @@ ++from cpython.object cimport PyObject ++ + cdef extern from "Python.h": +- ctypedef void PyObject + ############################################################################ + # 7.5.4 Method Objects + ############################################################################ +diff --git a/Cython/Includes/cpython/module.pxd b/Cython/Includes/cpython/module.pxd +index c821896..f36b989 100644 +--- a/Cython/Includes/cpython/module.pxd ++++ b/Cython/Includes/cpython/module.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + ctypedef struct _inittab +diff --git a/Cython/Includes/cpython/number.pxd b/Cython/Includes/cpython/number.pxd +index 346546e..3ad8de5 100644 +--- a/Cython/Includes/cpython/number.pxd ++++ b/Cython/Includes/cpython/number.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/object.pxd b/Cython/Includes/cpython/object.pxd +index d861965..6dc3022 100644 +--- a/Cython/Includes/cpython/object.pxd ++++ b/Cython/Includes/cpython/object.pxd +@@ -1,8 +1,61 @@ +-from cpython.ref cimport PyObject, PyTypeObject + from libc.stdio cimport FILE ++cimport cpython.type + + cdef extern from "Python.h": + ++ ctypedef struct PyObject # forward declaration ++ ++ ctypedef object (*newfunc)(cpython.type.type, object, object) # (type, args, kwargs) ++ ++ ctypedef object (*unaryfunc)(object) ++ ctypedef object (*binaryfunc)(object, object) ++ ctypedef object (*ternaryfunc)(object, object, object) ++ ctypedef int (*inquiry)(object) ++ ctypedef Py_ssize_t (*lenfunc)(object) ++ ctypedef object (*ssizeargfunc)(object, Py_ssize_t) ++ ctypedef object (*ssizessizeargfunc)(object, Py_ssize_t, Py_ssize_t) ++ ctypedef int (*ssizeobjargproc)(object, Py_ssize_t, object) ++ ctypedef int (*ssizessizeobjargproc)(object, Py_ssize_t, Py_ssize_t, object) ++ ctypedef int (*objobjargproc)(object, object, object) ++ ctypedef int (*objobjproc)(object, object) ++ ++ ctypedef Py_hash_t (*hashfunc)(object) ++ ctypedef object (*reprfunc)(object) ++ ++ # The following functions use 'PyObject*' as first argument instead of 'object' to prevent ++ # accidental reference counting when calling them during a garbage collection run. ++ ctypedef void (*destructor)(PyObject*) ++ ctypedef int (*visitproc)(PyObject*, void *) ++ ctypedef int (*traverseproc)(PyObject*, visitproc, void*) ++ ++ ctypedef struct PyTypeObject: ++ const char* tp_name ++ const char* tp_doc ++ Py_ssize_t tp_basicsize ++ Py_ssize_t tp_itemsize ++ Py_ssize_t tp_dictoffset ++ unsigned long tp_flags ++ ++ newfunc tp_new ++ destructor tp_dealloc ++ traverseproc tp_traverse ++ inquiry tp_clear ++ ++ ternaryfunc tp_call ++ hashfunc tp_hash ++ reprfunc tp_str ++ reprfunc tp_repr ++ ++ ctypedef struct PyObject: ++ Py_ssize_t ob_refcnt ++ PyTypeObject *ob_type ++ ++ cdef PyTypeObject *Py_TYPE(object) ++ ++ void* PyObject_Malloc(size_t) ++ void* PyObject_Realloc(void *, size_t) ++ void PyObject_Free(void *) ++ + ##################################################################### + # 6.1 Object Protocol + ##################################################################### +diff --git a/Cython/Includes/cpython/pycapsule.pxd b/Cython/Includes/cpython/pycapsule.pxd +index f0b326b..449f369 100644 +--- a/Cython/Includes/cpython/pycapsule.pxd ++++ b/Cython/Includes/cpython/pycapsule.pxd +@@ -1,4 +1,3 @@ +-from cpython.ref cimport PyObject + + # available since Python 3.1! + +diff --git a/Cython/Includes/cpython/pystate.pxd b/Cython/Includes/cpython/pystate.pxd +index d53259f..f58503f 100644 +--- a/Cython/Includes/cpython/pystate.pxd ++++ b/Cython/Includes/cpython/pystate.pxd +@@ -1,6 +1,6 @@ + # Thread and interpreter state structures and their interfaces + +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/ref.pxd b/Cython/Includes/cpython/ref.pxd +index 63ee54b..4bc9a7d 100644 +--- a/Cython/Includes/cpython/ref.pxd ++++ b/Cython/Includes/cpython/ref.pxd +@@ -1,15 +1,6 @@ +-cdef extern from "Python.h": +- ctypedef struct PyTypeObject: +- Py_ssize_t tp_basicsize +- Py_ssize_t tp_itemsize +- long tp_flags +- +- ctypedef struct PyObject: +- Py_ssize_t ob_refcnt +- PyTypeObject *ob_type +- cdef PyTypeObject *Py_TYPE(object) +- ++from cpython.object cimport PyObject, PyTypeObject, Py_TYPE # legacy imports for re-export + ++cdef extern from "Python.h": + ##################################################################### + # 3. Reference Counts + ##################################################################### +diff --git a/Cython/Includes/cpython/sequence.pxd b/Cython/Includes/cpython/sequence.pxd +index 61ddca2..eb27996 100644 +--- a/Cython/Includes/cpython/sequence.pxd ++++ b/Cython/Includes/cpython/sequence.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/string.pxd b/Cython/Includes/cpython/string.pxd +index 65c6d37..8af78f3 100644 +--- a/Cython/Includes/cpython/string.pxd ++++ b/Cython/Includes/cpython/string.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + ctypedef struct va_list +diff --git a/Cython/Includes/cpython/tuple.pxd b/Cython/Includes/cpython/tuple.pxd +index 6da2890..6564b50 100644 +--- a/Cython/Includes/cpython/tuple.pxd ++++ b/Cython/Includes/cpython/tuple.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/cpython/weakref.pxd b/Cython/Includes/cpython/weakref.pxd +index 8f51052..ae710be 100644 +--- a/Cython/Includes/cpython/weakref.pxd ++++ b/Cython/Includes/cpython/weakref.pxd +@@ -1,4 +1,4 @@ +-from cpython.ref cimport PyObject ++from cpython.object cimport PyObject + + cdef extern from "Python.h": + +diff --git a/Cython/Includes/numpy/__init__.pxd b/Cython/Includes/numpy/__init__.pxd +index edb1dbf..0ad89f7 100644 +--- a/Cython/Includes/numpy/__init__.pxd ++++ b/Cython/Includes/numpy/__init__.pxd +@@ -241,7 +241,6 @@ cdef extern from "numpy/arrayobject.h": + cdef int t + cdef char* f = NULL + cdef dtype descr = self.descr +- cdef list stack + cdef int offset + + cdef bint hasfields = PyDataType_HASFIELDS(descr) +@@ -788,8 +787,6 @@ cdef inline char* _util_dtypestring(dtype descr, char* f, char* end, int* offset + # string. The new location in the format string is returned. + + cdef dtype child +- cdef int delta_offset +- cdef tuple i + cdef int endian_detector = 1 + cdef bint little_endian = ((&endian_detector)[0] != 0) + cdef tuple fields diff --git a/src/sage/ext/python_rich_object.pxi b/src/sage/ext/python_rich_object.pxi deleted file mode 100644 index bfd275dc9c6..00000000000 --- a/src/sage/ext/python_rich_object.pxi +++ /dev/null @@ -1,46 +0,0 @@ -from cpython.ref cimport PyObject, PyTypeObject - -cdef extern from "Python.h": - ctypedef void (*freefunc)(void *) - ctypedef void (*destructor)(PyObject *) - ctypedef PyObject *(*getattrfunc)(PyObject *, char *) - ctypedef PyObject *(*getattrofunc)(PyObject *, PyObject *) - ctypedef int (*setattrfunc)(PyObject *, char *, PyObject *) - ctypedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *) - ctypedef int (*cmpfunc)(PyObject *, PyObject *) - ctypedef PyObject *(*reprfunc)(PyObject *) - ctypedef long (*hashfunc)(PyObject *) - ctypedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int) - ctypedef PyObject *(*getiterfunc) (PyObject *) - ctypedef PyObject *(*iternextfunc) (PyObject *) - ctypedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *) - ctypedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *) - ctypedef int (*initproc)(PyObject *, PyObject *, PyObject *) - ctypedef object (*newfunc)(PyTypeObject *, PyObject *, PyObject *) - ctypedef PyObject *(*allocfunc)(PyTypeObject *, Py_ssize_t) - - # We need a PyTypeObject with elements so we can - # get and set tp_new, tp_dealloc, tp_flags, and tp_basicsize - ctypedef struct RichPyTypeObject "PyTypeObject": - long tp_dictoffset - - allocfunc tp_alloc - newfunc tp_new - freefunc tp_free - destructor tp_dealloc - hashfunc tp_hash - richcmpfunc tp_richcompare - - #sizeof(Object) - Py_ssize_t tp_basicsize - - long tp_flags - - - cdef long Py_TPFLAGS_HAVE_GC - - # Allocation - PyObject* PyObject_MALLOC(int) - - # Free - void PyObject_FREE(PyObject*) diff --git a/src/sage/ext/pyx_visit.h b/src/sage/ext/pyx_visit.h new file mode 100644 index 00000000000..49bbe7328b7 --- /dev/null +++ b/src/sage/ext/pyx_visit.h @@ -0,0 +1,11 @@ +/* Cython-compatible version of Py_VISIT */ + +#define Pyx_VISIT(op) \ + do { \ + if (op) { \ + int vret = __pyx_v_visit((PyObject *)(op), __pyx_v_arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) + diff --git a/src/sage/ext/stdsage.pxd b/src/sage/ext/stdsage.pxd index 2a7ee094b3f..c3e07b4fee2 100644 --- a/src/sage/ext/stdsage.pxd +++ b/src/sage/ext/stdsage.pxd @@ -10,9 +10,8 @@ Standard C helper code for Cython modules # http://www.gnu.org/licenses/ #***************************************************************************** -include 'python_rich_object.pxi' -from cpython.ref cimport Py_TYPE - +from cpython.object cimport Py_TYPE, PyTypeObject +from cpython.type cimport type cdef inline PY_NEW(type t): """ @@ -20,7 +19,7 @@ cdef inline PY_NEW(type t): :class:`Integer` where we change ``tp_new`` at runtime (Cython optimizations assume that ``tp_new`` doesn't change). """ - return (t).tp_new(t, NULL, NULL) + return (t).tp_new(t, NULL, NULL) cdef inline void PY_SET_TP_NEW(type dst, type src): @@ -29,11 +28,11 @@ cdef inline void PY_SET_TP_NEW(type dst, type src): speed up Cython's boilerplate object construction code by skipping irrelevant base class ``tp_new`` methods. """ - (dst).tp_new = (src).tp_new + (dst).tp_new = (src).tp_new cdef inline bint HAS_DICTIONARY(obj): """ Test whether the given object has a Python dictionary. """ - return (Py_TYPE(obj)).tp_dictoffset != 0 + return Py_TYPE(obj).tp_dictoffset != 0 diff --git a/src/sage/libs/gmp/pylong.pxd b/src/sage/libs/gmp/pylong.pxd index d8c1c43b469..8691e9b7d9d 100644 --- a/src/sage/libs/gmp/pylong.pxd +++ b/src/sage/libs/gmp/pylong.pxd @@ -2,8 +2,6 @@ Various functions to deal with conversion mpz <-> Python int/long """ -from cpython.ref cimport PyTypeObject - cdef extern from "longintrepr.h": cdef _PyLong_New(Py_ssize_t s) cdef long PyLong_SHIFT diff --git a/src/sage/misc/allocator.pxd b/src/sage/misc/allocator.pxd index 3f73736b240..fce3179c626 100644 --- a/src/sage/misc/allocator.pxd +++ b/src/sage/misc/allocator.pxd @@ -1,2 +1,3 @@ -include "sage/ext/python_rich_object.pxi" -cdef hook_tp_functions(object global_dummy, allocfunc tp_alloc, newfunc tp_new, freefunc tp_free, destructor tp_dealloc, bint useGC) +from cpython.object cimport * + +cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_dealloc, bint useGC) diff --git a/src/sage/misc/allocator.pyx b/src/sage/misc/allocator.pyx index 331d0ddaa4a..1277f5a61d3 100644 --- a/src/sage/misc/allocator.pyx +++ b/src/sage/misc/allocator.pyx @@ -1,62 +1,13 @@ -include "sage/ext/interrupt.pxi" # ctrl-c interrupt block support -include "sage/ext/stdsage.pxi" -include "sage/ext/python.pxi" -from cpython.list cimport * -from cpython.number cimport * -from cpython.int cimport * -include "sage/ext/python_rich_object.pxi" +from cpython.ref cimport Py_INCREF -#def time_alloc_list(n): - #""" - #Allocate n a list of n Sage integers using PY_NEW. - #(Used for timing purposes.) - - #EXAMPLES: - #sage: from sage.rings.integer import time_alloc_list - #sage: v = time_alloc_list(100) - #""" - #cdef int i - #l = [] - #for i from 0 <= i < n: - #l.append(PY_NEW(Integer)) - - #return l - -#def time_alloc(n): - #""" - #Time allocating n integers using PY_NEW. - #Used for timing purposes. - - #EXAMPLES: - #sage: from sage.rings.integer import time_alloc - #sage: time_alloc(100) - #""" - #cdef int i - #for i from 0 <= i < n: - #z = PY_NEW(Integer) - -#def pool_stats(): - #""" - #Returns information about the Integer object pool. - - #EXAMPLES: - #sage: from sage.rings.integer import pool_stats - #sage: pool_stats() # random-ish output - #Used pool 0 / 0 times - #Pool contains 3 / 100 items - #""" - #return ["Used pool %s / %s times" % (use_pool, total_alloc), - #"Pool contains %s / %s items" % (integer_pool_count, integer_pool_size)] - -cdef hook_tp_functions(object global_dummy, allocfunc tp_alloc, newfunc tp_new, freefunc tp_free, destructor tp_dealloc, bint useGC): +cdef hook_tp_functions(object global_dummy, newfunc tp_new, destructor tp_dealloc, bint useGC): """ Initialize the fast integer creation functions. """ - cdef long flag cdef PyObject* o = global_dummy - cdef RichPyTypeObject* t = o.ob_type + cdef PyTypeObject* t = Py_TYPE(global_dummy) # Make sure this never, ever gets collected. # This is not necessary for cdef'ed variables as the global diff --git a/src/sage/misc/classcall_metaclass.pxd b/src/sage/misc/classcall_metaclass.pxd index b36f020c8b5..8597773f0de 100644 --- a/src/sage/misc/classcall_metaclass.pxd +++ b/src/sage/misc/classcall_metaclass.pxd @@ -5,9 +5,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -cdef extern from "object.h": - ctypedef class __builtin__.type [object PyHeapTypeObject]: - pass +from cpython.type cimport type from sage.misc.nested_class cimport NestedClassMetaclass diff --git a/src/sage/misc/classcall_metaclass.pyx b/src/sage/misc/classcall_metaclass.pyx index 6ef3f273203..11fd24ac079 100644 --- a/src/sage/misc/classcall_metaclass.pyx +++ b/src/sage/misc/classcall_metaclass.pyx @@ -17,12 +17,7 @@ AUTHORS: #***************************************************************************** include 'sage/ext/python.pxi' - -cdef extern from "Python.h": - ctypedef PyObject *(*callfunc)(type, object, object) except NULL - ctypedef struct PyTypeObject_call "PyTypeObject": - callfunc tp_call # needed to call type.__call__ at very high speed. - cdef PyTypeObject_call PyType_Type # Python's type +from cpython.object cimport * __all__ = ['ClasscallMetaclass', 'typecall', 'timeCall'] @@ -160,7 +155,7 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): """ cls.classcall = function - def __call__(cls, *args, **opts): + def __call__(cls, *args, **kwds): r""" This method implements ``cls()``. @@ -327,30 +322,10 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): ValueError: Calling classcall """ if cls.classcall is not None: - return cls.classcall(cls, *args, **opts) + return cls.classcall(cls, *args, **kwds) else: - ########################################################### - # This is type.__call__(cls, *args, **opts) twice faster - # Using the following test code: - # - # sage: class NOCALL(object): - # ... __metaclass__ = ClasscallMetaclass - # ... pass - # - # with type.__call__ : - # sage: %timeit [NOCALL() for i in range(10000)] - # 125 loops, best of 3: 3.59 ms per loop - # with this ugly C call: - # sage: %timeit [NOCALL() for i in range(10000)] - # 125 loops, best of 3: 1.76 ms per loop - # - # Note: compared to a standard void Python class the slow down is - # only 5%: - # sage: %timeit [Rien() for i in range(10000)] - # 125 loops, best of 3: 1.7 ms per loop - res = PyType_Type.tp_call(cls, args, opts) - Py_XDECREF(res) # During the cast to Cython did INCREF(res) - return res + # Fast version of type.__call__(cls, *args, **kwds) + return (type).tp_call(cls, args, kwds) def __get__(cls, instance, owner): r""" @@ -481,7 +456,7 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): return x in object -def typecall(type cls, *args, **opts): +def typecall(type cls, *args, **kwds): r""" Object construction @@ -514,10 +489,7 @@ def typecall(type cls, *args, **opts): ... TypeError: Argument 'cls' has incorrect type (expected type, got classobj) """ - # See remarks in ClasscallMetaclass.__call__(cls, *args, **opts) for speed. - res = PyType_Type.tp_call(cls, args, opts) - Py_XDECREF(res) # During the cast to Cython did INCREF(res) - return res + return (type).tp_call(cls, args, kwds) # Class for timing:: diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index b582f79a369..7eccb496225 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -37,7 +37,6 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.constant_function import ConstantFunction from sage.misc.lazy_attribute import lazy_class_attribute -include "sage/ext/python_rich_object.pxi" from cpython.bool cimport * from cpython.ref cimport * diff --git a/src/sage/misc/nested_class.pxd b/src/sage/misc/nested_class.pxd index 91081c88e50..14bbc68258a 100644 --- a/src/sage/misc/nested_class.pxd +++ b/src/sage/misc/nested_class.pxd @@ -1,6 +1,4 @@ -cdef extern from "object.h": - ctypedef class __builtin__.type [object PyHeapTypeObject]: - pass +from cpython.type cimport type cdef class NestedClassMetaclass(type): pass diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index 7a8810f0818..3deca28d939 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -119,8 +119,8 @@ from weakref import KeyedRef from copy import deepcopy from cpython.dict cimport * -from cpython.weakref cimport * -from cpython.list cimport * +from cpython.weakref cimport PyWeakref_NewRef +from cpython.list cimport PyList_New from cpython.object cimport PyObject_Hash from cpython cimport Py_XINCREF, Py_XDECREF diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index d8fc13805e6..e8098262416 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -144,6 +144,7 @@ from sage.ext.memory cimport check_allocarray from cpython.list cimport * from cpython.number cimport * from cpython.int cimport * +from cpython.object cimport * from libc.stdint cimport uint64_t cimport sage.structure.element from sage.structure.element cimport Element, EuclideanDomainElement, parent_c @@ -6523,8 +6524,6 @@ cdef class long_to_Z(Morphism): ############### INTEGER CREATION CODE ##################### -include "sage/ext/python_rich_object.pxi" - # This variable holds the size of any Integer object in bytes. cdef int sizeof_Integer @@ -6552,8 +6551,7 @@ cdef int total_alloc = 0 cdef int use_pool = 0 -cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): - +cdef PyObject* fast_tp_new(type t, args, kwds): global integer_pool, integer_pool_count, total_alloc, use_pool cdef PyObject* new @@ -6577,12 +6575,12 @@ cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): else: # allocate enough room for the Integer, sizeof_Integer is - # sizeof(Integer). The use of PyObject_MALLOC directly + # sizeof(Integer). The use of PyObject_Malloc directly # assumes that Integers are not garbage collected, i.e. # they do not possess references to other Python # objects (as indicated by the Py_TPFLAGS_HAVE_GC flag). # See below for a more detailed description. - new = PyObject_MALLOC( sizeof_Integer ) + new = PyObject_Malloc( sizeof_Integer ) # Now set every member as set in z, the global dummy Integer # created before this tp_new started to operate. @@ -6613,8 +6611,8 @@ cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): # case a Python object has a bunch of debugging fields which are # initialized with this macro. - if_Py_TRACE_REFS_then_PyObject_INIT\ - (new, (global_dummy_Integer).ob_type) + if_Py_TRACE_REFS_then_PyObject_INIT( + new, Py_TYPE(global_dummy_Integer)) # The global_dummy_Integer may have a reference count larger than # one, but it is expected that newly created objects have a @@ -6660,7 +6658,7 @@ cdef void fast_tp_dealloc(PyObject* o): # Free the object. This assumes that Py_TPFLAGS_HAVE_GC is not # set. If it was set another free function would need to be # called. - PyObject_FREE(o) + PyObject_Free(o) from sage.misc.allocator cimport hook_tp_functions cdef hook_fast_tp_functions(): @@ -6675,11 +6673,11 @@ cdef hook_fast_tp_functions(): o = global_dummy_Integer # store how much memory needs to be allocated for an Integer. - sizeof_Integer = (o.ob_type).tp_basicsize + sizeof_Integer = o.ob_type.tp_basicsize # Finally replace the functions called when an Integer needs # to be constructed/destructed. - hook_tp_functions(global_dummy_Integer, NULL, (&fast_tp_new), NULL, &fast_tp_dealloc, False) + hook_tp_functions(global_dummy_Integer, (&fast_tp_new), (&fast_tp_dealloc), False) cdef integer(x): if isinstance(x, Integer): @@ -6699,7 +6697,7 @@ def free_integer_pool(): # Free the object. This assumes that Py_TPFLAGS_HAVE_GC is not # set. If it was set another free function would need to be # called. - PyObject_FREE(o) + PyObject_Free(o) integer_pool_size = 0 integer_pool_count = 0 diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index cb69ac4c4aa..1bfe048b212 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -32,7 +32,15 @@ Test NumPy conversions:: dtype('float64') """ -from cpython.ref cimport PyObject, PyTypeObject +#***************************************************************************** +# 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 cpython.object cimport * from cpython.float cimport * include "sage/ext/python_debug.pxi" include 'sage/ext/cdefs.pxi' @@ -2636,8 +2644,6 @@ def is_RealDoubleElement(x): ########### Based on fast integer creation code ######### ######## There is nothing to see here, move along ####### -include "sage/ext/python_rich_object.pxi" - # We use a global element to steal all the references # from. DO NOT INITIALIZE IT AGAIN and DO NOT REFERENCE IT! cdef RealDoubleElement global_dummy_element @@ -2651,9 +2657,7 @@ global_dummy_element = RealDoubleElement(0) # if available, otherwise a new RealDoubleElement object is created # - When an element is collected, it will add it to the pool # if there is room, otherwise it will be deallocated. - -cdef enum: - element_pool_size = 50 # Pyrex has no way of defining constants +DEF element_pool_size = 50 cdef PyObject* element_pool[element_pool_size] cdef int element_pool_count = 0 @@ -2663,8 +2667,7 @@ cdef int total_alloc = 0 cdef int use_pool = 0 -cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): - +cdef PyObject* fast_tp_new(type t, args, kwds): global element_pool, element_pool_count, total_alloc, use_pool cdef PyObject* new @@ -2689,13 +2692,13 @@ cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): # allocate enough room for the RealDoubleElement, # sizeof_RealDoubleElement is sizeof(RealDoubleElement). - # The use of PyObject_MALLOC directly assumes + # The use of PyObject_Malloc directly assumes # that RealDoubleElements are not garbage collected, i.e. # they do not possess references to other Python # objects (As indicated by the Py_TPFLAGS_HAVE_GC flag). # See below for a more detailed description. - new = PyObject_MALLOC( sizeof(RealDoubleElement) ) + new = PyObject_Malloc( sizeof(RealDoubleElement) ) # Now set every member as set in z, the global dummy RealDoubleElement # created before this tp_new started to operate. @@ -2706,9 +2709,8 @@ cdef PyObject* fast_tp_new(PyTypeObject *t, PyObject *a, PyObject *k): # './configure --with-pydebug' or SAGE_DEBUG=yes. If that is the # case a Python object has a bunch of debugging fields which are # initialized with this macro. - - if_Py_TRACE_REFS_then_PyObject_INIT\ - (new, (global_dummy_element).ob_type) + if_Py_TRACE_REFS_then_PyObject_INIT( + new, Py_TYPE(global_dummy_element)) # The global_dummy_element may have a reference count larger than # one, but it is expected that newly created objects have a @@ -2741,11 +2743,11 @@ cdef void fast_tp_dealloc(PyObject* o): # set. If it was set another free function would need to be # called. - PyObject_FREE(o) + PyObject_Free(o) from sage.misc.allocator cimport hook_tp_functions -hook_tp_functions(global_dummy_element, NULL, (&fast_tp_new), NULL, &fast_tp_dealloc, False) +hook_tp_functions(global_dummy_element, (&fast_tp_new), (&fast_tp_dealloc), False) def time_alloc_list(n): diff --git a/src/sage/structure/coerce_dict.pyx b/src/sage/structure/coerce_dict.pyx index 3cf2ae13b39..9645dc9d3da 100644 --- a/src/sage/structure/coerce_dict.pyx +++ b/src/sage/structure/coerce_dict.pyx @@ -1,12 +1,3 @@ -#***************************************************************************** -# Copyright (C) 2007 Robert Bradshaw -# 2012 Simon King -# 2013 Nils Bruin -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# http://www.gnu.org/licenses/ -#***************************************************************************** """ Containers for storing coercion data @@ -38,9 +29,21 @@ parent (:trac:`12313`). By :trac:`14159`, :class:`MonoDict` and :class:`TripleDict` can be optionally used with weak references on the values. - """ -from cpython.list cimport * + +#***************************************************************************** +# Copyright (C) 2007 Robert Bradshaw +# 2012 Simon King +# 2013 Nils Bruin +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from cpython.object cimport * +from cpython.list cimport PyList_New from cpython.mem cimport * from cpython.string cimport PyString_FromString from cpython cimport Py_XINCREF, Py_XDECREF @@ -62,12 +65,10 @@ from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer cdef extern from "Python.h": PyObject* PyWeakref_GetObject(object r) PyObject* Py_None - int PyList_SetItem(object list, Py_ssize_t index,PyObject * item) except -1 + int PyList_SetItem(object list, Py_ssize_t index, PyObject * item) except -1 - ctypedef int (*visitproc)(PyObject* ob, void* arg) - ctypedef struct PyTypeObject: - void * tp_traverse - void * tp_clear +cdef extern from "pyx_visit.h": + void Pyx_VISIT(PyObject*) #this serves no purpose here anymore. Perhaps elsewhere? cpdef inline Py_ssize_t signed_id(x): @@ -842,21 +843,15 @@ cdef class MonoDict: #on cyclic GC) cdef int MonoDict_traverse(MonoDict op, visitproc visit, void *arg): - cdef int r if op.table == NULL: return 0 - table=op.table - cdef size_t i = 0 - if ((op.eraser)): - r=visit((op.eraser),arg) - if r: return r - for i in range(op.mask+1): - cursor = &table[i] + Pyx_VISIT(op.eraser) + cdef size_t i + for i in range(op.mask + 1): + cursor = &op.table[i] if cursor.key_id != NULL and cursor.key_id != dummy: - r=visit(cursor.key_weakref,arg) - if r: return r - r=visit(cursor.value,arg) - if r: return r + Pyx_VISIT(cursor.key_weakref) + Pyx_VISIT(cursor.value) return 0 @@ -893,8 +888,8 @@ cdef int MonoDict_clear(MonoDict op): PyMem_Free(table) return 0 -(MonoDict).tp_traverse = &MonoDict_traverse -(MonoDict).tp_clear = &MonoDict_clear +(MonoDict).tp_traverse = (&MonoDict_traverse) +(MonoDict).tp_clear = (&MonoDict_clear) cdef class TripleDictEraser: """ @@ -1560,25 +1555,17 @@ cdef class TripleDict: #on cyclic GC) cdef int TripleDict_traverse(TripleDict op, visitproc visit, void *arg): - cdef int r if op.table == NULL: return 0 - table=op.table - cdef size_t i = 0 - if ((op.eraser)): - r=visit((op.eraser),arg) - if r: return r - for i in range(op.mask+1): - cursor = &table[i] + Pyx_VISIT(op.eraser) + cdef size_t i + for i in range(op.mask + 1): + cursor = &op.table[i] if cursor.key_id1 != NULL and cursor.key_id1 != dummy: - r=visit(cursor.key_weakref1,arg) - if r: return r - r=visit(cursor.key_weakref2,arg) - if r: return r - r=visit(cursor.key_weakref3,arg) - if r: return r - r=visit(cursor.value,arg) - if r: return r + Pyx_VISIT(cursor.key_weakref1) + Pyx_VISIT(cursor.key_weakref2) + Pyx_VISIT(cursor.key_weakref3) + Pyx_VISIT(cursor.value) return 0 cdef int TripleDict_clear(TripleDict op): @@ -1607,5 +1594,5 @@ cdef int TripleDict_clear(TripleDict op): PyMem_Free(table) return 0 -(TripleDict).tp_traverse = &TripleDict_traverse -(TripleDict).tp_clear = &TripleDict_clear +(TripleDict).tp_traverse = (&TripleDict_traverse) +(TripleDict).tp_clear = (&TripleDict_clear) From e403f16cdb4e158c0533992c5588188dea46cd11 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 16 Apr 2015 10:21:07 +0200 Subject: [PATCH 300/665] trac #17464: broken doctests on (different architecture + bliss) --- .../en/prep/Quickstarts/Graphs-and-Discrete.rst | 2 +- src/sage/combinat/binary_tree.py | 6 ------ src/sage/combinat/ordered_tree.py | 15 +++++---------- src/sage/combinat/posets/posets.py | 12 ++++++------ src/sage/databases/sql_db.py | 8 +++++--- src/sage/groups/perm_gps/permgroup.py | 10 ++++++---- 6 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst b/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst index 948c99376dc..e756c8f7a19 100644 --- a/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst +++ b/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst @@ -122,7 +122,7 @@ cube. sage: Aut=C.automorphism_group() sage: print "Order of automorphism group: ", Aut.order() Order of automorphism group: 48 - sage: print "Group: \n", Aut + sage: print "Group: \n", Aut # random Group: Permutation Group with generators [('010','100')('011','101'), ('001','010')('101','110'), ('000','001')('010','011')('100','101')('110','111')] diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 2bdcca72b8f..f0c5513771f 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1226,12 +1226,6 @@ def to_undirected_graph(self, with_leaves=False): EXAMPLES:: sage: bt = BinaryTree([[],[None,[]]]) - sage: bt.canonical_labelling() - 2[1[., .], 3[., 4[., .]]] - sage: bt.canonical_labelling().to_undirected_graph().edges() - [(1, 2, None), (2, 3, None), (3, 4, None)] - sage: bt.to_undirected_graph().edges() - [(0, 3, None), (1, 2, None), (2, 3, None)] sage: bt.canonical_labelling().to_undirected_graph() == bt.to_undirected_graph() False sage: BinaryTree([[],[]]).to_undirected_graph() == BinaryTree([[[],None],None]).to_undirected_graph() diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 89b64a72b66..d061ad6df58 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -458,20 +458,15 @@ def to_poset(self, root_to_leaf = False): sage: t.to_poset() Finite poset containing 1 elements sage: p = OrderedTree([[[]],[],[]]).to_poset() - sage: p.cover_relations() - [[3, 4], [2, 4], [0, 1], [1, 4]] - sage: p = OrderedTree([[[]],[],[]]).to_poset(root_to_leaf=True) - sage: p.cover_relations() - [[0, 1], [0, 2], [0, 3], [3, 4]] + sage: p.height(), p.width() + (3, 3) If the tree is labelled, we use its labelling to label the poset. Otherwise, we use the poset canonical labelling:: - sage: t = OrderedTree([[[]],[],[]]).canonical_labelling() - sage: t - 1[2[3[]], 4[], 5[]] - sage: t.to_poset().cover_relations() - [[5, 1], [4, 1], [3, 2], [2, 1]] + sage: t = OrderedTree([[[]],[],[]]).canonical_labelling().to_poset() + sage: t.height(), t.width() + (3, 3) """ if self in LabelledOrderedTrees(): relabel = False diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index d6ca2c459cc..f9aac675052 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -3652,8 +3652,8 @@ def canonical_label(self): sage: Q = P.canonical_label() sage: Q.list() [0, 1, 2, 3, 4, 5] - sage: Q.cover_relations() - [[0, 1], [0, 2], [1, 4], [2, 3], [2, 4], [3, 5], [4, 5]] + sage: Q.is_isomorphic(P) + True As a facade:: @@ -3665,8 +3665,8 @@ def canonical_label(self): sage: Q = P.canonical_label() sage: Q.list() [0, 1, 2, 3, 4, 5] - sage: Q.cover_relations() - [[0, 1], [0, 2], [1, 4], [2, 3], [2, 4], [3, 5], [4, 5]] + sage: Q.is_isomorphic(P) + True TESTS:: @@ -3680,8 +3680,8 @@ def canonical_label(self): sage: Q = P.canonical_label() sage: Q.linear_extension() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: Q.cover_relations() - [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]] + sage: Q.is_isomorphic(P) + True """ P = Poset(DiGraph(self._hasse_diagram).canonical_label(), linear_extension=self._with_linear_extension, category=self.category(), facade=self._is_facade) diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 36da1ac8c41..2e27b38e2af 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -965,7 +965,7 @@ def __init__(self, filename=None, read_only=None, skeleton=None): ... if g not in labels[i]: ... labels[i].append(g) ... D.add_row('simon', (g.size(), g.graph6_string(), g.order())) - sage: D.show('simon') + sage: D.show('simon') # random edges graph6 vertices ------------------------------------------------------------ 0 ? 0 @@ -995,7 +995,9 @@ def __init__(self, filename=None, read_only=None, skeleton=None): sage: Q = SQLQuery(D, {'table_name':'simon', 'display_cols':['graph6'], 'expression':['vertices','=',4]}) sage: Q2 = SQLQuery(D, {'table_name':'simon', 'display_cols':['graph6'], 'expression':['edges','=',3]}) sage: Q = Q.intersect(Q2) - sage: Q.query_results() + sage: len(Q.query_results()) + 3 + sage: Q.query_results() # random [(u'CF', u'CF'), (u'CJ', u'CJ'), (u'CL', u'CL')] NOTE: The values of ``display_cols`` are always concatenated in @@ -1011,7 +1013,7 @@ def __init__(self, filename=None, read_only=None, skeleton=None): instance. We can load the file as an immutable database:: sage: E = SQLDatabase(replace_with_your_own_filepath + 'simon.db') - sage: E.show('simon') + sage: E.show('simon') # random edges graph6 vertices ------------------------------------------------------------ 0 ? 0 diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 14c34d7e17a..33a724ffb82 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -2962,10 +2962,10 @@ def blocks_all(self, representatives = True): sage: ag.blocks_all() [[0, 15]] - Now the full blocks:: + Now the full block:: - sage: ag.blocks_all(representatives = False) - [[[0, 15], [1, 16], [14, 19], [8, 17], [5, 10], [2, 12], [7, 18], [3, 13], [4, 9], [6, 11]]] + sage: sorted(ag.blocks_all(representatives = False)[0]) + [[0, 15], [1, 16], [2, 12], [3, 13], [4, 9], [5, 10], [6, 11], [7, 18], [8, 17], [14, 19]] TESTS:: @@ -3161,7 +3161,9 @@ def minimal_generating_set(self): sage: g = graphs.CompleteGraph(4) sage: g.relabel(['a','b','c','d']) - sage: g.automorphism_group().minimal_generating_set() + sage: mgs = g.automorphism_group().minimal_generating_set(); len(mgs) + 2 + sage: mgs # random [('b','d','c'), ('a','c','b','d')] From e86d27196b9cee5e2d53c282a51f401e2a00182a Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 16 Apr 2015 11:34:31 +0200 Subject: [PATCH 301/665] Various Cython code fixes --- src/sage/finance/time_series.pyx | 25 ++--- src/sage/libs/fplll/fplll.pxi | 3 +- src/sage/libs/fplll/fplll.pyx | 2 +- src/sage/matrix/matrix_sparse.pyx | 96 ++++--------------- .../numerical/backends/gurobi_backend.pyx | 4 +- src/sage/repl/inputhook.pyx | 10 +- .../rings/polynomial/polynomial_element.pyx | 2 +- src/sage/rings/power_series_ring_element.pyx | 2 +- src/sage/stats/hmm/chmm.pyx | 12 +-- 9 files changed, 44 insertions(+), 112 deletions(-) diff --git a/src/sage/finance/time_series.pyx b/src/sage/finance/time_series.pyx index 408aac66f62..aa639562259 100644 --- a/src/sage/finance/time_series.pyx +++ b/src/sage/finance/time_series.pyx @@ -36,24 +36,25 @@ AUTHOR: - William Stein """ -include "sage/ext/cdefs.pxi" +#***************************************************************************** +# Copyright (C) 2008 William Stein +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + include "sage/ext/stdsage.pxi" -include "sage/ext/random.pxi" from cpython.slice cimport PySlice_Check from cpython.string cimport * - -cdef extern from "math.h": - double exp(double) - double floor(double) - double log(double) - double pow(double, double) - double sqrt(double) - -cdef extern from "string.h": - void* memcpy(void* dst, void* src, size_t len) +from libc.math cimport exp, floor, log, pow, sqrt +from libc.string cimport memcpy cimport numpy as cnumpy +from sage.misc.randstate cimport randstate, current_randstate from sage.rings.integer import Integer from sage.rings.real_double import RDF from sage.modules.vector_real_double_dense cimport Vector_real_double_dense diff --git a/src/sage/libs/fplll/fplll.pxi b/src/sage/libs/fplll/fplll.pxi index ccb800611a7..9510acc5bd5 100644 --- a/src/sage/libs/fplll/fplll.pxi +++ b/src/sage/libs/fplll/fplll.pxi @@ -103,8 +103,7 @@ cdef extern from "fplll/fplll.h" namespace "fplll": LLLMethod method, FloatType floatType, int precision, int flags) - cdef struct BKZParam: - BKZParam() + cdef cppclass BKZParam: ZZ_mat[mpz_t]* b ZZ_mat[mpz_t]* u int blockSize diff --git a/src/sage/libs/fplll/fplll.pyx b/src/sage/libs/fplll/fplll.pyx index e7952e48779..ad7ab4be888 100644 --- a/src/sage/libs/fplll/fplll.pyx +++ b/src/sage/libs/fplll/fplll.pyx @@ -509,7 +509,7 @@ cdef class FP_LLL: _check_delta(delta) _check_precision(precision) - cdef BKZParam o = BKZParam() + cdef BKZParam o o.b = self._lattice o.delta = delta diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 4ebbf92b347..6c626eaacda 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -2,6 +2,16 @@ r""" Base class for sparse matrices """ +#***************************************************************************** +# 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/ +#***************************************************************************** + + +cimport cython cimport matrix cimport matrix0 from sage.structure.element cimport Element, RingElement, ModuleElement, Vector @@ -12,11 +22,6 @@ include 'sage/ext/stdsage.pxi' include 'sage/ext/python.pxi' include 'sage/ext/interrupt.pxi' -cdef extern from "Python.h": - PyObject* PyTuple_GET_ITEM0 "PyTuple_GET_ITEM" (PyObject* p, Py_ssize_t pos) - PyObject* PyList_GET_ITEM0 "PyList_GET_ITEM" (PyObject* list, Py_ssize_t i) - Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) - import sage.matrix.matrix_space @@ -352,11 +357,9 @@ cdef class Matrix_sparse(matrix.Matrix): cdef Py_ssize_t i, j, k if version == -1: for ij, x in data.iteritems(): - i = PyNumber_AsSsize_t(PyTuple_GET_ITEM0( ij, 0), NULL) - j = PyNumber_AsSsize_t(PyTuple_GET_ITEM0( ij, 1), NULL) - self.set_unsafe(i, j, x) + self.set_unsafe(ij[0], ij[1], x) else: - raise RuntimeError, "unknown matrix version (=%s)"%version + raise RuntimeError("unknown matrix version (=%s)"%version) cdef int _cmp_c_impl(self, Element right) except -2: return cmp(self._dict(), right._dict()) @@ -1089,70 +1092,11 @@ cdef class Matrix_sparse(matrix.Matrix): s[i] += a * v[j] return s -## def _echelon_in_place_classical(self): -## """ -## Replace this matrix by its echelon form. - -## INPUT: -## params -- ignored. -## """ -## # ALGORITHM: -## # Since we know nothing about the base field, we use a generic -## # algorithm. We first convert to a list of sparse rows, then -## # directly perform a generic echelon algorithm on that list of -## # rows. -## if self.fetch('in_echelon_form'): -## return -## K = self.base_ring() -## ONE = K(1) -## if not K.is_field(): -## raise ArithmeticError, "The base ring must be a field." -## X = self.rows() -## nrows = self.nrows() -## ncols = self.ncols() -## pivot_positions = [] -## start_row = 0 -## nrows = self.nrows() -## ncols = self.ncols() -## for c in range(ncols): -## N = [] -## for r in xrange(start_row, nrows): -## if X[r].first_nonzero_position() == c: -## N.append((X[r].num_nonzero(),r)) -## if len(N) == 0: -## continue -## N.sort() -## r = N[0][1] -## leading = X[r].first_nonzero_entry() -## if leading != 0: -## pivot_positions.append(c) -## # 1. Rescale -## X[r].rescale(ONE/leading) -## # 2. Swap -## X[r], X[start_row] = X[start_row], X[r] -## # 3. Clear column -## for i in range(nrows): -## if i != start_row: -## s = X[i][c] -## if s != 0: -## X[i] = X[i].add(X[start_row], -s) -## # endif -## start_row = start_row + 1 -## #endfor -## if self.is_immutable(): -## self.__pivots = pivot_positions -## E = Matrix_generic_sparse_from_rows(X) -## E.__pivots = pivot_positions -## self.__echelon_form = E -## misc.verbose("Finished generic echelon.",t) -## return E - -################################## -# Helper code - -cdef Py_ssize_t get_ij(v, Py_ssize_t i, int j): - return PyNumber_AsSsize_t(PyTuple_GET_ITEM0(PyList_GET_ITEM0(v, i), j), NULL) - -#cdef Py_ssize_t get_ij(v, Py_ssize_t i, int j): -# return PyNumber_AsSsize_t(PyTuple_GET_ITEM( -# PyList_GET_ITEM(v, i), j), NULL) + +@cython.boundscheck(False) +@cython.wraparound(False) +# Return v[i][j] where v is a list of tuples. +# No checking is done, make sure you feed it valid input! +cdef inline Py_ssize_t get_ij(v, Py_ssize_t i, Py_ssize_t j): + t = (v)[i] + return (t)[j] diff --git a/src/sage/numerical/backends/gurobi_backend.pyx b/src/sage/numerical/backends/gurobi_backend.pyx index b7705aa4845..dad05c44d5c 100644 --- a/src/sage/numerical/backends/gurobi_backend.pyx +++ b/src/sage/numerical/backends/gurobi_backend.pyx @@ -653,8 +653,8 @@ cdef class GurobiBackend(GenericBackend): sage: p.col_bounds(0) # optional - Gurobi (0.0, 5.0) """ - - cdef double lb[1], ub[1] + cdef double lb[1] + cdef double ub[1] error = GRBgetdblattrelement(self.model, "LB", index, lb) check(self.env, error) diff --git a/src/sage/repl/inputhook.pyx b/src/sage/repl/inputhook.pyx index 0a33651735c..6676b99f75e 100644 --- a/src/sage/repl/inputhook.pyx +++ b/src/sage/repl/inputhook.pyx @@ -20,20 +20,17 @@ disable Ctrl-C. include 'sage/ext/interrupt.pxi' cdef extern from 'pythonrun.h': - int (*PyOS_InputHook)() nogil except * + int (*PyOS_InputHook)() nogil except -1 cdef extern from 'intrcheck.h': int PyOS_InterruptOccurred() nogil -### See https://github.com/cython/cython/pull/313 -# from cpython.exc cimport PyErr_SetInterrupt -### workaround - void PyErr_SetInterrupt() nogil +from cpython.exc cimport PyErr_SetInterrupt from sage.repl.attach import reload_attached_files_if_modified -cdef int c_sage_inputhook() nogil except *: +cdef int c_sage_inputhook() nogil except -1: """ This is the C function that is installed as PyOS_InputHook """ @@ -43,7 +40,6 @@ cdef int c_sage_inputhook() nogil except *: with gil: sage_inputhook() sig_check() - return 0 def install(): """ diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 9b0c7b368a5..bea25dc7d06 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -2362,7 +2362,7 @@ cdef class Polynomial(CommutativeAlgebraElement): """ return self.parent().base_ring() - def base_extend(self, R): + cpdef base_extend(self, R): """ Return a copy of this polynomial but with coefficients in R, if there is a natural map from coefficient ring of self to R. diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 41a91080cb2..c7f4d8d2b20 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -258,7 +258,7 @@ cdef class PowerSeries(AlgebraElement): """ return codomain(self(im_gens[0])) - def base_extend(self, R): + cpdef base_extend(self, R): """ Return a copy of this power series but with coefficients in R. diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 0bf687808ba..bdacc8dde63 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -16,20 +16,12 @@ AUTHOR: include "sage/ext/cdefs.pxi" include "sage/ext/interrupt.pxi" -cdef extern from "math.h": - double log(double) - double sqrt(double) - double exp(double) - int isnormal(double) - int isfinite(double) - -import math +from libc.math cimport log, sqrt, exp, isnormal, isfinite, M_PI +cdef double sqrt2pi = sqrt(2*M_PI) from sage.misc.flatten import flatten from sage.matrix.matrix import is_Matrix -cdef double sqrt2pi = sqrt(2*math.pi) - from sage.finance.time_series cimport TimeSeries from sage.stats.intlist cimport IntList From 7fb5d0c433d36bf846d9cfb2cfae68475f042189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 16 Apr 2015 08:11:35 -0400 Subject: [PATCH 302/665] 11111: final doc improvements --- .../finite_dimensional_modules_with_basis.py | 10 ++++---- src/sage/modules/with_basis/subquotient.py | 23 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index b6e437801d0..c634bc6c689 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -219,7 +219,7 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): r""" - Construct a free quotient module ``self``/``submodule``. + Construct the quotient module ``self``/``submodule``. INPUT: @@ -232,9 +232,11 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate .. WARNING:: - At this point, only quotients by free submodules whose - basis admits a unitriangular echelon form are supported - (so that the quotient is also a free module). + 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:: diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 86096023a0a..50e0560a162 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -22,13 +22,19 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): - ``submodule`` -- a submodule of ``self`` - ``category`` -- a category (default: ``ModulesWithBasis(submodule.base_ring())``) - ``submodule`` is typically a :class:`SubmoduleWithBasis`. It - should implement a method ``reduce``. Futheremore its ``lift`` - method should have a method ``.cokernel_basis_indices`` that - computes the indexing set of a subset of the basis of ``self`` - that spans some supplementary of ``submodule`` in the ambient - space. Mathematically speaking, ``submodule`` should be a free - submodule whose basis can be put in unitriangular echelon form. + ``submodule`` should be a free submodule admitting a basis in + unitriangular echelon form. Typically ``submodule`` is a + :class:`SubmoduleWithBasis` as returned by + :meth:`Modules.WithBasis.ParentMethods.submodule`. + + The ``lift`` method should have a method + ``.cokernel_basis_indices`` that computes the indexing set of a + subset `B` of the basis of ``self`` that spans some supplementary + of ``submodule`` in ``self`` (typically the non characteristic + columns of the aforementioned echelon form). ``submodule`` should + further implement a ``submodule.reduce(x)`` method that returns + the unique element in the span of `B` which is equivalent to `x` + modulo ``submodule``. This is meant to be constructed via :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` @@ -36,7 +42,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): This differs from :class:`sage.rings.quotient_ring.QuotientRing` in the following ways: - - The submodule needs not be an ideal. If it is, the + - ``submodule`` needs not be an ideal. If it is, the transportation of the ring structure is taken care of by the ``Subquotients`` categories. @@ -50,6 +56,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): .. SEEALSO:: + - :meth:`Modules.WithBasis.ParentMethods.submodule` - :meth:`Modules.WithBasis.FiniteDimensional.ParentMethods.quotient_module` - :class:`SubmoduleWithBasis` - :class:`sage.rings.quotient_ring.QuotientRing` From 26e23ffc2733101e362f4449ea98b2650bc287bd Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 16 Apr 2015 14:16:57 +0200 Subject: [PATCH 303/665] Added check on length parameter and cast to Sage Integer in Abstract class constructor --- src/sage/coding/linear_code.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 46f9f0751bf..31c73453f95 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -472,8 +472,8 @@ def best_known_linear_code_www(n, k, F, verbose=False): Construction of a linear code [72,36,15] over GF(2): [1]: [73, 36, 16] Cyclic Linear Code over GF(2) - CyclicCode of length 73 with generating polynomial x^37 + x^36 + x^34 + - x^33 + x^32 + x^27 + x^25 + x^24 + x^22 + x^21 + x^19 + x^18 + x^15 + x^11 + + CyclicCode of length 73 with generating polynomial x^37 + x^36 + x^34 + x^33 + x^32 + x^27 + x^25 + x^24 + x^22 + x^21 + x^19 + x^18 + x^15 + x^11 x^10 + x^8 + x^7 + x^5 + x^3 + 1 [2]: [72, 36, 15] Linear Code over GF(2) Puncturing of [1] at 1 @@ -785,8 +785,20 @@ def __init__(self, base_field, length): False sage: print C.divisor() #long time 1 + + TESTS: + + If the length field is neither a Python int nor a Sage Integer, it will + raise an exception:: + + sage: C = CodeExample(GF(17), 10.0, 5, generator_matrix) + Traceback (most recent call last): + ... + ValueError: length must be a Python int or a Sage Integer """ - self._length = length + if not isinstance(length, (int, Integer)): + raise ValueError("length must be a Python int or a Sage Integer") + self._length = Integer(length) cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() facade_for = VectorSpace(base_field, self._length) self.Element = type(facade_for.an_element()) #for when we made this a non-facade parent From b877932445212ddfd72fd70079c53f17df6d5fd9 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 15:27:11 +0200 Subject: [PATCH 304/665] Trac 18211: fix arguments + doctests + cwd=SAGE_TMP --- src/sage/geometry/polyhedron/base_ZZ.py | 25 ++++++++++++++----------- src/sage/geometry/polyhedron/library.py | 1 + 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index dab2e0e0bea..c0a09ce3f95 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -188,7 +188,7 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, sage: P = Polyhedron(ambient_dim=3, vertices=[]) sage: P.ehrhart_polynomial() # optional - latte_int 0 - sage: parent(_) + sage: parent(_) # optional - latte_int Univariate Polynomial Ring in t over Rational Field Test options:: @@ -229,16 +229,13 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, if not self.is_lattice_polytope(): raise ValueError("this must be a lattice polytope") - from sage.misc.package import is_package_installed, package_mesg - if not is_package_installed('latte_int'): - raise ValueError("The package latte_int must be installed!\n" + package_mesg()) - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(QQ, 't') if self.is_empty(): return R.zero() from sage.misc.temporary_file import tmp_filename + from sage.misc.misc import SAGE_TMP from subprocess import Popen, PIPE in_str = self.cdd_Hrepresentation() @@ -254,9 +251,9 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, args.append('--irrational-primal') if irrational_all_primal: args.append('--irrational-all-primal') - if maxdet: + if maxdet is not None: maxdet = int(maxdet) - if maxdet < 0: + if maxdet < 1: raise ValueError("maxdet must be a positive integer") args.append('--maxdet={}'.format(maxdet)) if no_decomposition: @@ -265,16 +262,22 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, args.append('--cdd') args.append(in_filename) - latte_proc = Popen(args, stdin = PIPE, stdout=PIPE, stderr=PIPE) + try: + latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=str(SAGE_TMP)) + except OSError: + raise ValueError("The package latte_int must be installed (type " + "'sage -i latte_int') in a console or " + "'install_package('latte_int') at a Sage prompt)!\n") + ans, err = latte_proc.communicate() + if verbose: + print err + ret_code = latte_proc.poll() if ret_code: raise ValueError("LattE program 'count' ended with a nonzero value" "(={}). Here is the content of stderr:\n{}".format( ret_code, err)) - if verbose: - print err - return R(ans.splitlines()[-2]) @cached_method diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index f2f093f9f9b..4140f446400 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -177,6 +177,7 @@ def Birkhoff_polytope(self, n): sage: b3.is_lattice_polytope() True sage: p3 = b3.ehrhart_polynomial() # optional - latte_int + sage: p3 # optional - latte_int 1/8*t^4 + 3/4*t^3 + 15/8*t^2 + 9/4*t + 1 sage: [p3(i) for i in [1,2,3,4]] # optional - latte_int [6, 21, 55, 120] From 1ee5281fcc157a083bcdca71106562b056fcd27d Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 16:45:47 +0200 Subject: [PATCH 305/665] Trac 18211: much better `verbose` handling! --- src/sage/geometry/polyhedron/base_ZZ.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index c0a09ce3f95..0d1ff970c69 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -263,15 +263,13 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, args.append(in_filename) try: - latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=str(SAGE_TMP)) + latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=(None if verbose else PIPE), cwd=str(SAGE_TMP)) except OSError: raise ValueError("The package latte_int must be installed (type " "'sage -i latte_int') in a console or " "'install_package('latte_int') at a Sage prompt)!\n") ans, err = latte_proc.communicate() - if verbose: - print err ret_code = latte_proc.poll() if ret_code: From a9ce4616099f6d0a5fc3d8a80c3ae76dca5874c7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 16 Apr 2015 17:04:51 +0200 Subject: [PATCH 306/665] trac #18211: print stderr when verbose=False --- src/sage/geometry/polyhedron/base_ZZ.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 0d1ff970c69..2d8cb6b7a05 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -124,9 +124,9 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, Return the Ehrhart polynomial of this polyhedron. Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP - \cap \ZZ^d)`. Then E. Ehrhart proved in in 1962 that `L` coincide with a + \cap \ZZ^d)`. Then E. Ehrhart proved in in 1962 that `L` coincides with a rational polynomial of degree `d` for integer `t`. `L` is called the - *Ehrhart polynomial* of `P`. For more information see + *Ehrhart polynomial* of `P`. For more information see the :wikipedia:`Ehrhart_polynomial`. INPUT: @@ -273,9 +273,11 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, ret_code = latte_proc.poll() if ret_code: - raise ValueError("LattE program 'count' ended with a nonzero value" - "(={}). Here is the content of stderr:\n{}".format( - ret_code, err)) + msg = "LattE's program 'count' ended with a nonzero value (={})".format(ret_code) + if not verbose: + msg += "Here is the content of stderr:\n"+err + raise ValueError(msg) + return R(ans.splitlines()[-2]) @cached_method From 930791639042e46c339ba40720456d73dcad1d1b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 17:32:33 +0200 Subject: [PATCH 307/665] Trac 18211: "in in" -> "in" --- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 2d8cb6b7a05..96d32359b91 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -124,7 +124,7 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, Return the Ehrhart polynomial of this polyhedron. Let `P` be a lattice polytope in `\RR^d` and define `L(P,t) = \# (tP - \cap \ZZ^d)`. Then E. Ehrhart proved in in 1962 that `L` coincides with a + \cap \ZZ^d)`. Then E. Ehrhart proved in 1962 that `L` coincides with a rational polynomial of degree `d` for integer `t`. `L` is called the *Ehrhart polynomial* of `P`. For more information see the :wikipedia:`Ehrhart_polynomial`. From dce923e806cdd021b1b0f5a427870cf76f7bed6e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 16 Apr 2015 12:10:26 -0400 Subject: [PATCH 308/665] Fixing cases when the action should also precompose with a coercion. --- src/sage/structure/coerce.pyx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6756c9c1b3f..1c03538ecc3 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1456,6 +1456,12 @@ cdef class CoercionModel_cache_maps(CoercionModel): To: Finite Field of size 5 sage: cm.bin_op(GF(5)['x'].gen(), 7, operator.div).parent() Univariate Polynomial Ring in x over Finite Field of size 5 + + Bug :trac:`18221`:: + + sage: F. = FreeAlgebra(QQ) + sage: x / 2 + 1/2*x """ #print "looking", R, R, op, S, S @@ -1510,7 +1516,11 @@ cdef class CoercionModel_cache_maps(CoercionModel): right_mul = self.get_action(R, S, mul) if right_mul and not right_mul.is_left(): try: - return ~right_mul + action = ~right_mul + if action.right_domain() != S: + action = PrecomposedAction(action, None, + action.right_domain()._internal_coerce_map_from(S)) + return action except TypeError: # action may not be invertible self._record_exception() From a6d03cd0f21b5c7438ec6b03e82fb6ba7536c414 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 18:13:00 +0200 Subject: [PATCH 309/665] Trac 18211: any option to the command (using **kwds) --- src/sage/geometry/polyhedron/base_ZZ.py | 45 ++++++++++++++----------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 96d32359b91..bcbde9bb871 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -118,8 +118,7 @@ def is_lattice_polytope(self): """ return True - def ehrhart_polynomial(self, dual=None, irrational_primal=None, - irrational_all_primal=None, maxdet=None, no_decomposition=None, verbose=False): + def ehrhart_polynomial(self, verbose=False, **kwds): r""" Return the Ehrhart polynomial of this polyhedron. @@ -131,6 +130,12 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, INPUT: + - ``verbose`` - (boolean, default to ``False``) if ``True``, print the + whole output of the LattE command. + + The following options are passed to the LattE command, for details you + should consult LattE documentation: + - ``dual`` - (boolean) triangulate and signed-decompose in the dual space @@ -145,8 +150,16 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, - ``no_decomposition`` -- (boolean) do not signed-decompose simplicial cones. - - ``verbose`` - (boolean, default to ``False``) if ``True``, print the - whole output of the LattE command. + - ``compute_vertex_cones`` -- (string) either 'cdd' or 'lrs' or '4ti2' + + - ``smith_form`` -- (string) either 'ilio' or 'lidia' + + - ``dualization`` -- (string) either 'cdd' or '4ti2' + + - ``triangulation`` - (string) 'cddlib', '4ti2' or 'topcom' + + - ``triangulation_max_height`` - (integer) use a uniform distribution of + height from 1 to this number ALGORITHM: @@ -244,21 +257,15 @@ def ehrhart_polynomial(self, dual=None, irrational_primal=None, in_file.write(self.cdd_Hrepresentation()) in_file.close() - args = ['count', '--ehrhart-polynomial', '--redundancy-check=none'] - if dual: - args.append('--dual') - if irrational_primal: - args.append('--irrational-primal') - if irrational_all_primal: - args.append('--irrational-all-primal') - if maxdet is not None: - maxdet = int(maxdet) - if maxdet < 1: - raise ValueError("maxdet must be a positive integer") - args.append('--maxdet={}'.format(maxdet)) - if no_decomposition: - args.append('--no-decomposition') - + args = ['count', '--ehrhart-polynomial'] + if 'redundancy_check' not in kwds: + args.append('--redundancy-check=none') + for key,value in kwds.iteritems(): + key = key.replace('_','-') + if value is True: + args.append('--{}'.format(key)) + elif value is not False: + args.append('--{}={}'.format(key, value)) args.append('--cdd') args.append(in_filename) From 6b2e9bbd832fdd672e6b5b36e457926305ce482d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 16 Apr 2015 12:26:49 -0400 Subject: [PATCH 310/665] Added test which checks the action map. --- src/sage/structure/coerce.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 1c03538ecc3..78f38a358be 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1462,6 +1462,11 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: F. = FreeAlgebra(QQ) sage: x / 2 1/2*x + sage: cm.discover_action(F, ZZ, operator.div) + Right inverse action by Rational Field on Free Algebra on 1 generators (x,) over Rational Field + with precomposition on right by Natural morphism: + From: Integer Ring + To: Rational Field """ #print "looking", R, R, op, S, S From c935177688734f81eec5dd96a1d85c76e7239df6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 18:27:52 +0200 Subject: [PATCH 311/665] Trac 18211: handle bad output from count --- src/sage/geometry/polyhedron/base_ZZ.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index bcbde9bb871..fec7c4563bc 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -204,6 +204,8 @@ def ehrhart_polynomial(self, verbose=False, **kwds): sage: parent(_) # optional - latte_int Univariate Polynomial Ring in t over Rational Field + TESTS: + Test options:: sage: P = Polyhedron(ieqs=[[1,-1,1,0], [-1,2,-1,0], [1,1,-2,0]], eqns=[[-1,2,-1,-3]], base_ring=ZZ) @@ -238,6 +240,13 @@ def ehrhart_polynomial(self, verbose=False, **kwds): Invocation: count --ehrhart-polynomial '--redundancy-check=none' --irrational-all-primal --cdd ... sage: p # optional - latte_int 1/2*t^2 + 3/2*t + 1 + + Test bad options:: + + sage: P.ehrhart_polynomial(bim_bam_boum=19) + Traceback (most recent call last): + ... + RuntimeError: Something is wrong with LattE command count with options {'bim_bam_boum': 19} """ if not self.is_lattice_polytope(): raise ValueError("this must be a lattice polytope") @@ -285,7 +294,12 @@ def ehrhart_polynomial(self, verbose=False, **kwds): msg += "Here is the content of stderr:\n"+err raise ValueError(msg) - return R(ans.splitlines()[-2]) + try: + p = ans.splitlines()[-2] + except IndexError: + raise RuntimeError("Something is wrong with LattE command count with options {}".format(kwds)) + + return R(p) @cached_method def polar(self): From 7215956eea81f8750a96184ca1f16173ef27c334 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 18:40:22 +0200 Subject: [PATCH 312/665] Trac 18211: write explicitely the options in function declaration --- src/sage/geometry/polyhedron/base_ZZ.py | 28 ++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index fec7c4563bc..09ff79c600b 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -118,7 +118,11 @@ def is_lattice_polytope(self): """ return True - def ehrhart_polynomial(self, verbose=False, **kwds): + def ehrhart_polynomial(self, verbose=False, dual=None, + irrational_primal=None, irrational_all_primal=None, maxdet=None, + no_decomposition=None, compute_vertex_cones=None, smith_form=None, + dualization=None, triangulation=None, triangulation_max_height=None, + **kwds): r""" Return the Ehrhart polynomial of this polyhedron. @@ -269,11 +273,29 @@ def ehrhart_polynomial(self, verbose=False, **kwds): args = ['count', '--ehrhart-polynomial'] if 'redundancy_check' not in kwds: args.append('--redundancy-check=none') - for key,value in kwds.iteritems(): + + # note: the options below are explicitely written in the function + # declaration in order to keep tab completion (see #18211). + kwds['dual'] = dual + kwds['irrational_primal'] = irrational_primal + kwds['irrational_all_primal'] = irrational_all_primal + kwds['maxdet'] = maxdet + kwds['no_decomposition'] = no_decomposition + kwds['compute_vertex_cones'] = compute_vertex_cones + kwds['smith_form'] = smith_form + kwds['dualization'] = dualization + kwds['triangulation'] = triangulation + kwds['triangulation_max_height'] = triangulation_max_height + + for key,value in kwds.items(): + if value is None or value is False: + kwds.pop(key) + continue + key = key.replace('_','-') if value is True: args.append('--{}'.format(key)) - elif value is not False: + else: args.append('--{}={}'.format(key, value)) args.append('--cdd') args.append(in_filename) From 74ef0f1721a9f73dacf442d29c45acc7a18a1ff6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 16 Apr 2015 19:19:33 +0200 Subject: [PATCH 313/665] trac #18211: Nothing important --- src/sage/geometry/polyhedron/base_ZZ.py | 45 +++++++++++++------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 09ff79c600b..125039f89df 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -138,7 +138,8 @@ def ehrhart_polynomial(self, verbose=False, dual=None, whole output of the LattE command. The following options are passed to the LattE command, for details you - should consult LattE documentation: + should consult `the LattE documentation + `__: - ``dual`` - (boolean) triangulate and signed-decompose in the dual space @@ -165,6 +166,11 @@ def ehrhart_polynomial(self, verbose=False, dual=None, - ``triangulation_max_height`` - (integer) use a uniform distribution of height from 1 to this number + .. NOTE:: + + Any additional argument is forwarded to LattE's executable + ``count``. All occurrences of '_' will be replaced with a '-'. + ALGORITHM: This method calls the program ``count`` from LattE integrale, a program @@ -250,7 +256,9 @@ def ehrhart_polynomial(self, verbose=False, dual=None, sage: P.ehrhart_polynomial(bim_bam_boum=19) Traceback (most recent call last): ... - RuntimeError: Something is wrong with LattE command count with options {'bim_bam_boum': 19} + RuntimeError: Something went wrong (see output above) when running: + count --ehrhart-polynomial --redundancy-check=none --bim-bam-boum=19 --cdd ... + """ if not self.is_lattice_polytope(): raise ValueError("this must be a lattice polytope") @@ -276,20 +284,20 @@ def ehrhart_polynomial(self, verbose=False, dual=None, # note: the options below are explicitely written in the function # declaration in order to keep tab completion (see #18211). - kwds['dual'] = dual - kwds['irrational_primal'] = irrational_primal - kwds['irrational_all_primal'] = irrational_all_primal - kwds['maxdet'] = maxdet - kwds['no_decomposition'] = no_decomposition - kwds['compute_vertex_cones'] = compute_vertex_cones - kwds['smith_form'] = smith_form - kwds['dualization'] = dualization - kwds['triangulation'] = triangulation - kwds['triangulation_max_height'] = triangulation_max_height + kwds.update({ + 'dual' : dual, + 'irrational_primal' : irrational_primal, + 'irrational_all_primal' : irrational_all_primal, + 'maxdet' : maxdet, + 'no_decomposition' : no_decomposition, + 'compute_vertex_cones' : compute_vertex_cones, + 'smith_form' : smith_form, + 'dualization' : dualization, + 'triangulation' : triangulation, + 'triangulation_max_height': triangulation_max_height}) for key,value in kwds.items(): if value is None or value is False: - kwds.pop(key) continue key = key.replace('_','-') @@ -309,17 +317,12 @@ def ehrhart_polynomial(self, verbose=False, dual=None, ans, err = latte_proc.communicate() - ret_code = latte_proc.poll() - if ret_code: - msg = "LattE's program 'count' ended with a nonzero value (={})".format(ret_code) - if not verbose: - msg += "Here is the content of stderr:\n"+err - raise ValueError(msg) - try: p = ans.splitlines()[-2] except IndexError: - raise RuntimeError("Something is wrong with LattE command count with options {}".format(kwds)) + if not verbose: + print err + raise RuntimeError("Something went wrong (see output above) when running:\n{}".format(' '.join(args))) return R(p) From 3ec20b4245a23f27931b00e54256743709e38e18 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 01:54:29 +0200 Subject: [PATCH 314/665] Trac 18215: Faster hash for quadratic number fields --- .../number_field_element_quadratic.pyx | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index a5ba2d3132e..32e1acc684f 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -46,6 +46,9 @@ from sage.rings.number_field.number_field_element import _inverse_mod_generic import number_field + +from sage.libs.gmp.pylong cimport mpz_pythonhash + # TODO: this doesn't belong here, but robert thinks it would be nice # to have globally available.... # @@ -1298,17 +1301,41 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def __hash__(self): """ - Return hash of this number field element, which is just the - hash of the underlying polynomial. + Return hash of this number field element. - EXAMPLE:: + For elements in `\ZZ` or `\QQ` the hash coincides with the one in the + native `\ZZ` or `\QQ`. + + EXAMPLES:: sage: L. = QuadraticField(-7) sage: hash(a) - 1505322287 # 32-bit - 15360174650385711 # 64-bit - """ - return hash(self.polynomial()) + 42082631 + + sage: hash(L(1)) + 1 + sage: hash(L(-3)) + -3 + + sage: hash(L(-32/118)) + -53 + sage: hash(-32/118) + -53 + """ + # 1. compute the hash of a/denom as if it was a rational + # (see the corresponding code in sage/rings/rational.pyx) + cdef long a_hash = mpz_pythonhash(self.a) + cdef long d_hash = mpz_pythonhash(self.denom) + if d_hash != 1: + a_hash ^= d_hash + if a_hash == -1: + a_hash == -2 + + # 2. mix them together with b + a_hash += 42082631 * mpz_pythonhash(self.b) + if a_hash == -1: + return -2 + return a_hash def __nonzero__(self): From 9b14aa5fcf1684960c93984ef74860d6c26cb1ac Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 16 Apr 2015 16:08:49 -0400 Subject: [PATCH 315/665] Change in docstring. --- src/sage/structure/coerce.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 78f38a358be..e553cea49a5 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1447,7 +1447,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): From: Integer Ring To: Rational Field - Bug :trac:`17740`:: + Check that :trac:`17740` is fixed:: sage: cm.discover_action(GF(5)['x'], ZZ, operator.div) Right inverse action by Finite Field of size 5 on Univariate Polynomial Ring in x over Finite Field of size 5 @@ -1457,7 +1457,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: cm.bin_op(GF(5)['x'].gen(), 7, operator.div).parent() Univariate Polynomial Ring in x over Finite Field of size 5 - Bug :trac:`18221`:: + Check that :trac:`18221` is fixed:: sage: F. = FreeAlgebra(QQ) sage: x / 2 From ef5819e6acfa30dd3aa8a8583dcd1d198b0e9839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Fri, 17 Apr 2015 00:26:27 +0200 Subject: [PATCH 316/665] Updating the documentation of permutahedron and bubble sort graph. Each object now have a 'See also' section mentioning the other one. The permutahedron now have a test if the underlying graph is isomorphic to the bubble sort graph. --- src/sage/geometry/polyhedron/library.py | 13 +++++++++++++ src/sage/graphs/generators/families.py | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 288073b3f75..21084e5e4ef 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -581,6 +581,9 @@ def permutahedron(self, n, project = True): The standard permutahedron of (1,...,n) projected into n-1 dimensions. + If we take the graph in which the vertices correspond to vertices of the + polyhedron, and edges to edges, we get the bubble sort graph. + INPUT: - ``n`` -- the numbers ``(1,...,n)`` are permuted @@ -598,6 +601,16 @@ def permutahedron(self, n, project = True): A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices sage: polytopes.permutahedron(5).plot() # long time Graphics3d Object + + .. SEEALSO:: + + * :meth:`~sage.graphs.graph_generators.GraphGenerators.BubbleSortGraph` + + TESTS:: + + sage: perm4 = polytopes.permutahedron(4) + sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) + True """ verts = range(1,n+1) verts = Permutations(verts).list() diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 3c40ebda429..45d416ac587 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -370,6 +370,8 @@ def BubbleSortGraph(n): `1 \leq i \leq n-1`. In total, `B(n)` has order `n!`. Thus, the order of `B(n)` increases according to `f(n) = n!`. + The bubble sort graph is the underlying graph of the permutahedron. + INPUT: - ``n`` -- positive integer. The number of symbols to permute. @@ -398,6 +400,10 @@ def BubbleSortGraph(n): sage: g.order() == factorial(n) True + .. SEEALSO:: + + * :meth:`~sage.geometry.polyhedron.library.Polytopes.permutahedron` + TESTS: Input ``n`` must be positive:: From 57fcc7951c7ad0f2c7252943da308f20301d7d37 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 16 Apr 2015 20:13:24 -0400 Subject: [PATCH 317/665] implement product by coercion in sfa.py --- src/sage/combinat/sf/sfa.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 078f5c8da88..12ecb96bf99 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2561,6 +2561,31 @@ def from_polynomial(self, poly, check=True): m = self.realization_of().m() return self(m.from_polynomial(poly, check=check)) + def product_by_coercion(self, left, right): + r""" + Return the product of elements ``left`` and ``right`` by coercion to + the Schur basis. + + INPUT: + + - ``left``, ``right`` -- instances of this basis + + OUTPUT: + + - the product of ``left`` and ``right`` expressed in the basis ``self`` + + EXAMPLES:: + + sage: p = SymmetricFunctions(QQ).p() + sage: p.product_by_coercion(p[3,1,1], p[2,2]) + p[3, 2, 2, 1, 1] + sage: m = SymmetricFunctions(QQ).m() + sage: m.product_by_coercion(m[2,1],m[1,1]) == m[2,1]*m[1,1] + True + """ + s = self.realization_of().schur() + return self(s.product(left,right)) + def coproduct_by_coercion(self, elt): r""" Return the coproduct of the element ``elt`` by coercion to From 0ad062c139f1ecc4b87cd67f22a3c55765e81a0b Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 16 Apr 2015 20:20:40 -0400 Subject: [PATCH 318/665] converted left and right to s basis first --- 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 12ecb96bf99..8a9e30669e2 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2584,7 +2584,7 @@ def product_by_coercion(self, left, right): True """ s = self.realization_of().schur() - return self(s.product(left,right)) + return self(s.product(s(left),s(right))) def coproduct_by_coercion(self, elt): r""" From 29230dac580e52dac67730fd0f617af198559495 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Fri, 17 Apr 2015 06:34:34 +0200 Subject: [PATCH 319/665] Trac #18235: Inconsistent indentation in module_list.py --- src/module_list.py | 189 +++++++++++++++++++++++---------------------- 1 file changed, 95 insertions(+), 94 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d4db0acf81d..d8cf213862d 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -304,40 +304,40 @@ def uname_specific(name, value, alternative): libraries = ['pari', 'gmp'], extra_compile_args = ['-std=c99']), - ################################ - ## - ## sage.games - ## - ################################ + ################################ + ## + ## sage.games + ## + ################################ - Extension('sage.games.sudoku_backtrack', - sources = ['sage/games/sudoku_backtrack.pyx']), + Extension('sage.games.sudoku_backtrack', + sources = ['sage/games/sudoku_backtrack.pyx']), - ################################ - ## - ## sage.geometry - ## - ################################ + ################################ + ## + ## sage.geometry + ## + ################################ - Extension('sage.geometry.point_collection', - sources = ['sage/geometry/point_collection.pyx']), + Extension('sage.geometry.point_collection', + sources = ['sage/geometry/point_collection.pyx']), - Extension('sage.geometry.toric_lattice_element', - sources = ['sage/geometry/toric_lattice_element.pyx'], - libraries=['gmp']), + Extension('sage.geometry.toric_lattice_element', + sources = ['sage/geometry/toric_lattice_element.pyx'], + libraries=['gmp']), - Extension('sage.geometry.integral_points', - sources = ['sage/geometry/integral_points.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.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++"), ################################ ## @@ -486,11 +486,11 @@ def uname_specific(name, value, alternative): sources = ['sage/graphs/hyperbolicity.pyx'], libraries = ['gmp']), - ################################ - ## - ## sage.graphs.base - ## - ################################ + ################################ + ## + ## sage.graphs.base + ## + ################################ Extension('sage.graphs.base.c_graph', sources = ['sage/graphs/base/c_graph.pyx'], @@ -525,11 +525,11 @@ def uname_specific(name, value, alternative): Extension('sage.groups.semimonomial_transformations.semimonomial_transformation', sources = ['sage/groups/semimonomial_transformations/semimonomial_transformation.pyx']), - ################################### - ## - ## sage.groups.perm_gps.partn_ref - ## - ################################### + ################################### + ## + ## sage.groups.perm_gps.partn_ref + ## + ################################### Extension('sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label', sources = ['sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx'], @@ -585,11 +585,11 @@ def uname_specific(name, value, alternative): extra_compile_args = ['-std=c99'], depends = flint_depends), - ################################### - ## - ## sage.groups.perm_gps.partn_ref2 - ## - ################################### + ################################### + ## + ## sage.groups.perm_gps.partn_ref2 + ## + ################################### Extension('sage.groups.perm_gps.partn_ref2.refinement_generic', sources = ['sage/groups/perm_gps/partn_ref2/refinement_generic.pyx'], @@ -850,11 +850,11 @@ def uname_specific(name, value, alternative): sources = ["sage/libs/mpmath/ext_libmp.pyx"], libraries = ['gmp']), - ################################ - ## - ## sage.libs.gap - ## - ################################ + ################################ + ## + ## sage.libs.gap + ## + ################################ Extension('sage.libs.gap.util', sources = ["sage/libs/gap/util.pyx"], @@ -868,11 +868,11 @@ def uname_specific(name, value, alternative): sources = ["sage/libs/gap/libgap.pyx"], libraries = ['gmp', 'gap', 'm']), - ################################### - ## - ## sage.libs.cremona - ## - ################################### + ################################### + ## + ## sage.libs.cremona + ## + ################################### Extension('sage.libs.cremona.homspace', sources = ["sage/libs/cremona/homspace.pyx"], @@ -908,11 +908,11 @@ def uname_specific(name, value, alternative): "oldforms.h","homspace.h","cperiods.h","newforms.h"] ]), - ################################### - ## - ## sage.libs.ntl - ## - ################################### + ################################### + ## + ## sage.libs.ntl + ## + ################################### Extension('sage.libs.ntl.error', sources = ["sage/libs/ntl/error.pyx"], @@ -1526,12 +1526,12 @@ def uname_specific(name, value, alternative): sources = ['sage/rings/real_interval_absolute.pyx'], libraries = ['gmp']), - OptionalExtension("sage.rings.real_arb", - ["sage/rings/real_arb.pyx"], - libraries = ['arb', 'mpfi', 'mpfr'], - include_dirs = [SAGE_INC + '/flint'], - depends = flint_depends, - package = 'arb'), + OptionalExtension("sage.rings.real_arb", + ["sage/rings/real_arb.pyx"], + libraries = ['arb', 'mpfi', 'mpfr'], + include_dirs = [SAGE_INC + '/flint'], + depends = flint_depends, + package = 'arb'), Extension('sage.rings.real_lazy', sources = ['sage/rings/real_lazy.pyx']), @@ -1554,11 +1554,11 @@ def uname_specific(name, value, alternative): sources = ['sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c.pyx'], libraries = ['gmp']), - ################################ - ## - ## sage.rings.finite_rings - ## - ################################ + ################################ + ## + ## sage.rings.finite_rings + ## + ################################ Extension('sage.rings.finite_rings.finite_field_base', sources = ['sage/rings/finite_rings/finite_field_base.pyx']), @@ -1599,20 +1599,20 @@ def uname_specific(name, value, alternative): language='c++', extra_compile_args = givaro_extra_compile_args), - ################################ - ## - ## sage.rings.function_field - ## - ################################ + ################################ + ## + ## sage.rings.function_field + ## + ################################ Extension('sage.rings.function_field.function_field_element', sources = ['sage/rings/function_field/function_field_element.pyx']), - ################################ - ## - ## sage.rings.number_field - ## - ################################ + ################################ + ## + ## sage.rings.number_field + ## + ################################ Extension('sage.rings.number_field.number_field_base', sources = ['sage/rings/number_field/number_field_base.pyx']), @@ -1638,11 +1638,11 @@ def uname_specific(name, value, alternative): sources = ['sage/rings/number_field/totallyreal_data.pyx'], libraries = ['gmp']), - ################################ - ## - ## sage.rings.padics - ## - ################################ + ################################ + ## + ## sage.rings.padics + ## + ################################ Extension('sage.rings.padics.morphism', sources = ['sage/rings/padics/morphism.pyx']), @@ -1710,11 +1710,11 @@ def uname_specific(name, value, alternative): libraries = ["ntl", "gmp", "gmpxx", "m"], language='c++'), - ################################ - ## - ## sage.rings.polynomial - ## - ################################ + ################################ + ## + ## sage.rings.polynomial + ## + ################################ Extension('sage.rings.polynomial.cyclotomic', sources = ['sage/rings/polynomial/cyclotomic.pyx']), @@ -1830,11 +1830,11 @@ def uname_specific(name, value, alternative): Extension('sage.rings.polynomial.symmetric_reduction', sources = ['sage/rings/polynomial/symmetric_reduction.pyx']), - ################################ - ## - ## sage.rings.semirings - ## - ################################ + ################################ + ## + ## sage.rings.semirings + ## + ################################ Extension('sage.rings.semirings.tropical_semiring', sources = ['sage/rings/semirings/tropical_semiring.pyx']), @@ -1997,6 +1997,7 @@ def uname_specific(name, value, alternative): ## sage.tests ## ################################ + Extension('sage.tests.interrupt', sources = ['sage/tests/interrupt.pyx', 'sage/tests/c_lib.c']), From 80456d80dafe26adf7ac95e71311c767ca5e866b Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 17 Apr 2015 08:23:58 +0200 Subject: [PATCH 320/665] trac 18185: missing ':' --- 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 d438e4b2742..14563d2e9a8 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1347,7 +1347,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.name(data.name()) self.add_vertices(data.vertices()) self.add_edges(data.edge_iterator()) - elif format == 'NX' + elif format == 'NX': if convert_empty_dict_labels_to_None is not False: r = lambda x:None if x=={} else x else: From 835d82b85a8b2a53711223e88641bc4b6da8c7cd Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Fri, 17 Apr 2015 09:27:26 +0200 Subject: [PATCH 321/665] pynac-0.3.5 --- build/pkgs/pynac/checksums.ini | 6 +++--- build/pkgs/pynac/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pynac/checksums.ini b/build/pkgs/pynac/checksums.ini index b2e6a7c42f1..7158e457051 100644 --- a/build/pkgs/pynac/checksums.ini +++ b/build/pkgs/pynac/checksums.ini @@ -1,4 +1,4 @@ tarball=pynac-VERSION.tar.bz2 -sha1=d7a80f5c96eec3ac9ecb6757d004e460fbfecece -md5=70fae63e2c1cb4ec13eea24a4a780ba8 -cksum=1408069708 +sha1=79821599bdaff04ee09e9ed007c93279789022ab +md5=97fed71054f5cd931c44dcf3ab3089c6 +cksum=3283787374 diff --git a/build/pkgs/pynac/package-version.txt b/build/pkgs/pynac/package-version.txt index d15723fbe8d..c2c0004f0e2 100644 --- a/build/pkgs/pynac/package-version.txt +++ b/build/pkgs/pynac/package-version.txt @@ -1 +1 @@ -0.3.2 +0.3.5 From f8c9f8ef8662324dee8f1bc403968fa5b2d168aa Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 17 Apr 2015 10:33:44 +0200 Subject: [PATCH 322/665] trac #18185: combinat decided that we can't sort vertices in DiGraph.__init__ --- src/sage/graphs/digraph.py | 2 +- src/sage/graphs/generic_graph.py | 2 +- src/sage/graphs/graph.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index c3d035ee0e2..295dd6988e2 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -780,7 +780,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = data.weighted() if data.get_pos() is not None: pos = data.get_pos().copy() - self.add_vertices(data.vertices()) + self.add_vertices(data.vertex_iterator()) self.add_edges(data.edge_iterator()) self.name(data.name()) elif format == 'rule': diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 3090b03969b..f0a964accf7 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3050,7 +3050,7 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): TESTS:: sage: Graph({'H': ['G','L','L','D'], 'L': ['G','D']}).eulerian_circuit(labels=False) - [('H', 'L'), ('L', 'H'), ('H', 'G'), ('G', 'L'), ('L', 'D'), ('D', 'H')] + [('H', 'D'), ('D', 'L'), ('L', 'G'), ('G', 'H'), ('H', 'L'), ('L', 'H')] sage: Graph({0: [0, 1, 1, 1, 1]}).eulerian_circuit(labels=False) [(0, 1), (1, 0), (0, 1), (1, 0), (0, 0)] """ diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 14563d2e9a8..c03d87e7898 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1345,7 +1345,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data.get_pos() is not None: pos = data.get_pos().copy() self.name(data.name()) - self.add_vertices(data.vertices()) + self.add_vertices(data.vertex_iterator()) self.add_edges(data.edge_iterator()) elif format == 'NX': if convert_empty_dict_labels_to_None is not False: From 0b87ff0df3007581999081a3aafbbc4fd2cca47c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 02:19:52 +0200 Subject: [PATCH 323/665] Trac 18213: rewrite the polyhedron library --- src/sage/geometry/polyhedron/library.py | 1112 ++++++++++++++--------- 1 file changed, 699 insertions(+), 413 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 4140f446400..02a18d39c45 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -1,6 +1,42 @@ r""" Library of commonly used, famous, or interesting polytopes +This module gathers several constructors of polytopes that can be reached +through ``polytopes.``. For example, here is the hypercube in dimension 5:: + + sage: polytopes.hypercube(5) + A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 32 vertices + +The following constructions are available + +.. csv-table:: + :class: contentstable + :widths: 30 + :delim: | + + :meth:`~sage.geometry.polyhedron.library.Polytopes.Birkhoff_polytope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.buckyball` + :meth:`~sage.geometry.polyhedron.library.Polytopes.cross_polytope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.cube` + :meth:`~sage.geometry.polyhedron.library.Polytopes.cuboctahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.cyclic_polytope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.dodecahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.flow_polytope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.great_rhombicuboctahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.hypercube` + :meth:`~sage.geometry.polyhedron.library.Polytopes.hypersimplex` + :meth:`~sage.geometry.polyhedron.library.Polytopes.icosahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.Kirkman_icosahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.parallelotope` + :meth:`~sage.geometry.polyhedron.library.Polytopes.pentakis_dodecahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.permutahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.regular_polygon` + :meth:`~sage.geometry.polyhedron.library.Polytopes.rhombic_dodecahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.simplex` + :meth:`~sage.geometry.polyhedron.library.Polytopes.six_hundred_cell` + :meth:`~sage.geometry.polyhedron.library.Polytopes.small_rhombicuboctahedron` + :meth:`~sage.geometry.polyhedron.library.Polytopes.twenty_four_cell` + REFERENCES: .. [Fetter2012] @@ -11,159 +47,158 @@ ######################################################################## # Copyright (C) 2008 Marshall Hampton -# Copyright (C) 2011 Volker Braun +# 2011 Volker Braun +# 2015 Vincent Delecroix <20100.delecroix@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ ######################################################################## +import itertools -from sage.rings.all import Integer, RR, QQ, RDF -from sage.matrix.constructor import matrix -from sage.modules.free_module_element import vector +from sage.rings.all import Integer, ZZ, RR, QQ, RDF, AA, QQbar from sage.combinat.permutation import Permutations from sage.groups.perm_gps.permgroup_named import AlternatingGroup -from sage.misc.functional import norm -from sage.functions.other import sqrt from sage.misc.decorators import rename_keyword +from sage.misc.superseded import deprecated_function_alias from constructor import Polyhedron from sage.graphs.digraph import DiGraph -######################################################################### -class Polytopes(): - """ - A class of constructors for commonly used, famous, or interesting - polytopes. +def zero_sum_projection(dim): + r""" + Return a matrix corresponding to the projection on the orthogonal of + `(1,1,\ldots,1)` in dimension `dim`. - TESTS:: + EXAMPLES:: - sage: TestSuite(polytopes).run(skip='_test_pickling') + sage: from sage.geometry.polyhedron.library import zero_sum_projection + sage: zero_sum_projection(2) + [ 0.7071067811865475 -0.7071067811865475] + sage: zero_sum_projection(3) + [ 0.7071067811865475 -0.7071067811865475 0.0] + [ 0.4082482904638631 0.4082482904638631 -0.8164965809277261] """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + basis = [vector(RDF,[1]*i + [-i] + [0]*(dim-i-1)) for i in range(1,dim)] + return matrix(RDF, [v / v.norm() for v in basis]) - @staticmethod - def orthonormal_1(dim_n=5): - """ - A matrix of rational approximations to orthonormal vectors to - ``(1,...,1)``. +def project_points(*points): + """ + Projects a set of points into a vector space of dimension one less. - INPUT: + The projection is isometric to the orthogonal projection on the hyperplane + made of zero sum vector. Hence, if the set of points have all equal sums, + then their projection is isometric (as a set of points). - - ``dim_n`` - the dimension of the vectors + EXAMPLES:: - OUTPUT: + sage: from sage.geometry.polyhedron.library import project_points + sage: project_points([2,-1,3,2]) + [(2.1213203435596424, -2.041241452319315, -0.577350269189626)] + sage: project_points([1,2,3],[3,3,5]) + [(-0.7071067811865475, -1.2247448713915892), (0.0, -1.6329931618554523)] - A matrix over ``QQ`` whose rows are close to an orthonormal - basis to the subspace normal to ``(1,...,1)``. + This projection is the only one compatible with the restriction to the first + coordinates:: - EXAMPLES:: + sage: project_points([1,2]) + [(-0.7071067811865475)] + sage: project_points([1,2,3]) + [(-0.7071067811865475, -1.2247448713915892)] + sage: project_points([1,2,3,4]) + [(-0.7071067811865475, -1.2247448713915892, -1.7320508075688776)] + + Check that it is (almost) an isometry:: + + sage: V = map(vector, IntegerVectors(n=5,length=3)) + sage: P = project_points(*V) + sage: for i in range(21): + ....: for j in range(21): + ....: assert abs((V[i]-V[j]).norm() - (P[i]-P[j]).norm()) < 0.00001 + """ + if not points: + return + from sage.modules.free_module_element import vector + vecs = [vector(RDF,p) for p in points] + m = zero_sum_projection(len(vecs[0])) + return [m*v for v in vecs] - sage: from sage.geometry.polyhedron.library import Polytopes - sage: m = Polytopes.orthonormal_1(5) - sage: m - [ 70711/100000 -7071/10000 0 0 0] - [ 1633/4000 1633/4000 -81649/100000 0 0] - [ 7217/25000 7217/25000 7217/25000 -43301/50000 0] - [ 22361/100000 22361/100000 22361/100000 22361/100000 -44721/50000] - """ - pb = [] - for i in range(0,dim_n-1): - pb.append([1.0/(i+1)]*(i+1) + [-1] + [0]*(dim_n-i-2)) - m = matrix(RDF,pb) - new_m = [] - for i in range(0,dim_n-1): - new_m.append([RDF(100000*q/norm(m[i])).ceil()/100000 for q in m[i]]) - return matrix(QQ,new_m) +class Polytopes(): + """ + A class of constructors for commonly used, famous, or interesting + polytopes. + """ flow_polytope = staticmethod(DiGraph.flow_polytope) - @staticmethod - def project_1(fpoint): + def regular_polygon(self, n, exact=True, base_ring=None): """ - Take a ndim-dimensional point and projects it onto the plane - perpendicular to (1,1,...,1). + Return a regular polygon with `n` vertices. INPUT: - - ``fpoint`` - a list of ndim numbers - - EXAMPLES:: + - ``n`` -- a positive integer, the number of vertices. - sage: from sage.geometry.polyhedron.library import Polytopes - sage: Polytopes.project_1([1,1,1,1,2]) - [1/100000, 1/100000, 1/50000, -559/625] - """ - dim_n = len(fpoint) - p_basis = [list(q) for q in Polytopes.orthonormal_1(dim_n)] - out_v = [] - for v in p_basis: - out_v.append(sum([fpoint[ind]*v[ind] for ind in range(dim_n)])) - return out_v + - ``exact`` -- (boolean, default ``True``) if ``False`` floating point + numbers are used for coordinates. - @staticmethod - def _pfunc(i,j,perm): - """ - An internal utility function for constructing the Birkhoff polytopes. + - ``base_ring`` -- a ring in which the coordinates will lie. It is + ``None`` by default. If it is not provided and ``exact`` is ``True`` + then it will be the field of real algebraic number, if ``exact`` is + ``False`` it will be the real double field. EXAMPLES:: - sage: from sage.geometry.polyhedron.library import Polytopes - sage: Polytopes._pfunc(1,2,Permutations(3)[0]) - 0 - """ - if perm[i-1] == j: - return 1 - else: - return 0 + sage: octagon = polytopes.regular_polygon(8) + sage: octagon + A 2-dimensional polyhedron in AA^2 defined as the convex hull of 8 vertices + sage: octagon.n_vertices() + 8 + sage: v = octagon.volume() + sage: v + 2.828427124746190? + sage: v == 2*QQbar(2).sqrt() + True + Its non exact version:: - @rename_keyword(deprecation=11634, field='base_ring') - def regular_polygon(self, n, base_ring=QQ): + sage: polytopes.regular_polygon(3, exact=False).vertices() + (A vertex at (0.0, 1.0), + A vertex at (0.8660254038, -0.5), + A vertex at (-0.8660254038, -0.5)) + sage: polytopes.regular_polygon(25, exact=False).n_vertices() + 25 """ - Return a regular polygon with `n` vertices. Over the rational - field the vertices may not be exact. + n = ZZ(n) + if n <= 2: + raise ValueError("n (={}) must be an integer greater than 2".format(n)) - INPUT: + if base_ring is None: + if exact: + base_ring = AA + else: + base_ring = RDF - - ``n`` -- a positive integer, the number of vertices. - - - ``base_ring`` -- a ring in which the coordinates will lie. - - EXAMPLES:: - - sage: octagon = polytopes.regular_polygon(8) - sage: len(octagon.vertices()) - 8 - sage: polytopes.regular_polygon(3).vertices() - (A vertex at (-125283617/144665060, -500399958596723/1000799917193445), - A vertex at (0, 1), - A vertex at (94875313/109552575, -1000799917193444/2001599834386889)) - sage: polytopes.regular_polygon(3, base_ring=RealField(100)).vertices() - (A vertex at (0.00000000000000000000000000000, 1.0000000000000000000000000000), - A vertex at (0.86602540378443864676372317075, -0.50000000000000000000000000000), - A vertex at (-0.86602540378443864676372317076, -0.50000000000000000000000000000)) - sage: polytopes.regular_polygon(3, base_ring=RealField(10)).vertices() - (A vertex at (0.00, 1.0), - A vertex at (0.87, -0.50), - A vertex at (-0.86, -0.50)) - """ try: - omega = 2*base_ring.pi()/n + omega = 2*base_ring.pi() / n + verts = [((i*omega).sin(), (i*omega).cos()) for i in range(n)] except AttributeError: - omega = 2*RR.pi()/n - verts = [] - for i in range(n): - t = omega*i - verts.append([base_ring(t.sin()), base_ring(t.cos())]) - return Polyhedron(vertices=verts, base_ring=base_ring) + z = QQbar.zeta(n) + verts = [(base_ring((z**k).imag()), base_ring((z**k).real())) for k in range(n)] + return Polyhedron(vertices=verts, base_ring=base_ring) def Birkhoff_polytope(self, n): """ - Return the Birkhoff polytope with `n!` vertices. Each vertex - is a (flattened) n by n permutation matrix. + Return the Birkhoff polytope with `n!` vertices. + + The vertices of this polyhedron are the (flattened) `n` by `n` + permutation matrices. So the ambient vector space has dimension `n^2` + but the dimension of the polyhedron is `(n-1)^2`. INPUT: @@ -172,8 +207,10 @@ def Birkhoff_polytope(self, n): EXAMPLES:: sage: b3 = polytopes.Birkhoff_polytope(3) - sage: b3.n_vertices() - 6 + sage: b3.f_vector() + (1, 6, 15, 18, 9, 1) + sage: print b3.ambient_dim(), b3.dim() + 9 4 sage: b3.is_lattice_polytope() True sage: p3 = b3.ehrhart_polynomial() # optional - latte_int @@ -185,278 +222,480 @@ def Birkhoff_polytope(self, n): [6, 21, 55, 120] sage: b4 = polytopes.Birkhoff_polytope(4) - sage: b4.n_vertices() == factorial(4) - True + sage: print b4.n_vertices(), b4.ambient_dim(), b4.dim() + 24 16 9 """ from itertools import permutations verts = [] for p in permutations(range(n)): - verts.append( [int(p[i]==j) for j in range(n) for i in range(n) ] ) - return Polyhedron(vertices=verts) + verts.append( [ZZ.one() if p[i]==j else ZZ.zero() for j in range(n) for i in range(n) ] ) + return Polyhedron(vertices=verts, base_ring=ZZ) - def n_simplex(self, dim_n=3, project = True): + @rename_keyword(deprecation=18213, dim_n='dim') + def simplex(self, dim=3, project=False): """ - Return a rational approximation to a regular simplex in - dimension ``dim_n``. + Return the ``dim`` dimensional simplex. + + The `d`-simplex is the convex hull in `\RR^{d+1}` of the standard basis + `(1,0,\ldots,0)`, `(0,1,\ldots,0)`, \ldots, `(0,0,\ldots,1)`. For more + information, see the :wikipedia:`Simplex`. INPUT: - - ``dim_n`` -- The dimension of the simplex, a positive + - ``dim`` -- The dimension of the simplex, a positive integer. - - ``project`` -- Optional argument, whether to project - orthogonally. Default is True. + - ``project`` -- (boolean, default ``False``) if ``True``, the polytope + is (isometrically) projected to a vector space of dimension ``dim-1``. + This operation turns the coordinates into floating point + approximations. - OUTPUT: + EXAMPLES:: - A Polyhedron object of the ``dim_n``-dimensional simplex. + sage: s5 = polytopes.simplex(5) + sage: s5 + A 5-dimensional polyhedron in ZZ^6 defined as the convex hull of 6 vertices + sage: s5.f_vector() + (1, 6, 15, 20, 15, 6, 1) - EXAMPLES:: + sage: s5 = polytopes.simplex(5, project=True) + sage: s5 + A 5-dimensional polyhedron in RDF^5 defined as the convex hull of 6 vertices - sage: s5 = polytopes.n_simplex(5) - sage: s5.dim() - 5 + Its volume is `\sqrt{d+1} / d!`:: + + sage: s5 = polytopes.simplex(5, project=True) + sage: s5.volume() + 0.020412414522984975 + sage: sqrt(6.) / factorial(5) + 0.0204124145231931 + + sage: s6 = polytopes.simplex(6, project=True) + sage: s6.volume() + 0.003674654598885692 + sage: sqrt(7.) / factorial(6) + 0.00367465459870082 """ - verts = Permutations([0 for i in range(dim_n)] + [1]).list() - if project: verts = [Polytopes.project_1(x) for x in verts] + verts = list((ZZ ** (dim+1)).basis()) + if project: verts = project_points(*verts) return Polyhedron(vertices=verts) + n_simplex = deprecated_function_alias(18213, simplex) - @rename_keyword(deprecation=11634, field='base_ring') - def icosahedron(self, base_ring=QQ): + def icosahedron(self, exact=True, base_ring=None): """ Return an icosahedron with edge length 1. - INPUT: + The icosahedron is one of the Platonic sold. It has 20 faces and is dual + to the Dodecahedron. - - ``base_ring`` -- Either ``QQ`` or ``RDF``. + .. SEEALSO:: - OUTPUT: + :meth:`dodecahedron` + + INPUT: - A Polyhedron object of a floating point or rational - approximation to the regular 3d icosahedron. + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. - If ``base_ring=QQ``, a rational approximation is used and the - points are not exactly the vertices of the icosahedron. The - icosahedron's coordinates contain the golden ratio, so there - is no exact representation possible. + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: sage: ico = polytopes.icosahedron() - sage: sum(sum( ico.vertex_adjacency_matrix() ))/2 - 30 - """ - if base_ring == QQ: - g = QQ(1618033)/1000000 # Golden ratio approximation - r12 = QQ(1)/2 - elif base_ring == RDF: - g = RDF( (1 + sqrt(5))/2 ) - r12 = RDF( QQ(1)/2 ) + sage: ico.f_vector() + (1, 12, 30, 20, 1) + sage: ico.volume() + 5/12*sqrt5 + 5/4 + + Its non exact version:: + + sage: ico = polytopes.icosahedron(exact=False) + sage: ico.base_ring() + Real Double Field + sage: ico.volume() + 2.1816949907715726 + """ + if base_ring is None and exact: + from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') + sqrt5 = K.gen() + g = (1 + sqrt5) / 2 + base_ring = K else: - raise ValueError("field must be QQ or RDF.") - verts = [i([0,r12,g/2]) for i in AlternatingGroup(3)] - verts = verts + [i([0,r12,-g/2]) for i in AlternatingGroup(3)] - verts = verts + [i([0,-r12,g/2]) for i in AlternatingGroup(3)] - verts = verts + [i([0,-r12,-g/2]) for i in AlternatingGroup(3)] + if base_ring is None: + base_ring = RDF + g = (1 + base_ring(5).sqrt()) / 2 + + r12 = base_ring.one() / 2 + z = base_ring.zero() + pts = [[z, s1*r12, s2*g/2] for s1,s2 in itertools.product([1,-1],repeat=2)] + verts = [p(v) for p in AlternatingGroup(3) for v in pts] return Polyhedron(vertices=verts, base_ring=base_ring) - @rename_keyword(deprecation=11634, field='base_ring') - def dodecahedron(self, base_ring=QQ): + def dodecahedron(self, exact=True, base_ring=None): """ Return a dodecahedron. + .. SEEALSO:: + + :meth:`icosahedron` + INPUT: - - ``base_ring`` -- Either ``QQ`` (in which case a rational - approximation to the golden ratio is used) or ``RDF``. + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. + + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: sage: d12 = polytopes.dodecahedron() - sage: d12.n_inequalities() - 12 - """ - return self.icosahedron(base_ring=base_ring).polar() + sage: d12.f_vector() + (1, 20, 30, 12, 1) + sage: d12.volume() + -176*sqrt5 + 400 + sage: numerical_approx(_) + 6.45203596003699 + sage: d12 = polytopes.dodecahedron(exact=False) + sage: d12.base_ring() + Real Double Field + """ + return self.icosahedron(exact=exact).polar() - def small_rhombicuboctahedron(self): + def small_rhombicuboctahedron(self, exact=True, base_ring=None): """ - Return an Archimedean solid with 24 vertices and 26 faces. + Return the (small) rhombicuboctahedron. + + The rhombicuboctahedron is an Archimedean solid with 24 vertices and 26 + faces. See the :wikipedia:`Rhombicuboctahedron` for more information. + + INPUT: + + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. + + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: sage: sr = polytopes.small_rhombicuboctahedron() - sage: sr.n_vertices() - 24 - sage: sr.n_inequalities() - 26 - """ - verts = [ [-3/2, -1/2, -1/2], [-3/2, -1/2, 1/2], [-3/2, 1/2, -1/2], - [-3/2, 1/2, 1/2], [-1/2, -3/2, -1/2], [-1/2, -3/2, 1/2], - [-1/2, -1/2, -3/2], [-1/2,-1/2, 3/2], [-1/2, 1/2, -3/2], - [-1/2, 1/2, 3/2], [-1/2, 3/2, -1/2], [-1/2, 3/2, 1/2], - [1/2, -3/2, -1/2], [1/2, -3/2, 1/2], [1/2, -1/2,-3/2], - [1/2, -1/2, 3/2], [1/2, 1/2, -3/2], [1/2, 1/2, 3/2], - [1/2, 3/2,-1/2], [1/2, 3/2, 1/2], [3/2, -1/2, -1/2], - [3/2, -1/2, 1/2], [3/2, 1/2,-1/2], [3/2, 1/2, 1/2] ] + sage: sr.f_vector() + (1, 24, 48, 26, 1) + sage: sr.volume() + 80/3*sqrt2 + 32 + + The faces are `8` equilateral triangles and `18` squares:: + + sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 3) + 8 + sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 4) + 18 + + Its non exact version:: + + sage: sr = polytopes.small_rhombicuboctahedron(False) + sage: sr + A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 + vertices + sage: sr.f_vector() + (1, 24, 48, 26, 1) + """ + if base_ring is None and exact: + from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(2, 'sqrt2') + sqrt2 = K.gen() + base_ring = K + else: + if base_ring is None: + base_ring = RDF + sqrt2 = base_ring(2).sqrt() + + one = base_ring.one() + a = sqrt2 + one + verts = [] + verts.extend([s1*one, s2*one, s3*a] for s1,s2,s3 in itertools.product([1,-1], repeat=3)) + verts.extend([s1*one, s3*a, s2*one] for s1,s2,s3 in itertools.product([1,-1], repeat=3)) + verts.extend([s1*a, s2*one, s3*one] for s1,s2,s3 in itertools.product([1,-1], repeat=3)) return Polyhedron(vertices=verts) - @rename_keyword(deprecation=11634, field='base_ring') - def great_rhombicuboctahedron(self, base_ring=QQ): + def great_rhombicuboctahedron(self, exact=True, base_ring=None): """ - Return an Archimedean solid with 48 vertices and 26 faces. + Return the great rhombicuboctahedron. + + The great rohombicuboctahedron (or truncated cuboctahedron) is an + Archimedean solid with 48 vertices and 26 faces. For more information + see the :wikipedia:`Truncated_cuboctahedron`. + + INPUT: + + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. + + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: - sage: gr = polytopes.great_rhombicuboctahedron() - sage: gr.n_vertices() - 48 - sage: gr.n_inequalities() - 26 - """ - v1 = QQ(131739771357/54568400000) - v2 = QQ(104455571357/27284200000) - verts = [ [1, v1, v2], - [1, v2, v1], - [v1, 1, v2], - [v1, v2, 1], - [v2, 1, v1], - [v2, v1, 1] ] - verts = verts + [[x[0],x[1],-x[2]] for x in verts] - verts = verts + [[x[0],-x[1],x[2]] for x in verts] - verts = verts + [[-x[0],x[1],x[2]] for x in verts] - if base_ring!=QQ: - verts = [base_ring(v) for v in verts] - return Polyhedron(vertices=verts, base_ring=base_ring) + sage: gr = polytopes.great_rhombicuboctahedron() # long time ~ 3sec + sage: gr.f_vector() # long time + (1, 48, 72, 26, 1) + A faster implementation is obtained by setting ``exact=False``:: + + sage: gr = polytopes.great_rhombicuboctahedron(exact=False) + sage: gr.f_vector() + (1, 48, 72, 26, 1) + + Its faces are 4 squares, 8 regular hexagons and 6 regular octagons:: + + sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 4) + 12 + sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 6) + 8 + sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 8) + 6 + """ + if base_ring is None and exact: + from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(2, 'sqrt2') + sqrt2 = K.gen() + base_ring = K + else: + if base_ring is None: + base_ring = RDF + sqrt2 = base_ring(2).sqrt() + + one = base_ring.one() + v1 = sqrt2 + 1 + v2 = 2*sqrt2 + 1 + verts = [ [s1*z1, s2*z2, s3*z3] + for z1,z2,z3 in itertools.permutations([one,v1,v2]) + for s1,s2,s3 in itertools.product([1,-1], repeat=3)] + return Polyhedron(vertices=verts, base_ring=base_ring) def rhombic_dodecahedron(self): """ - This face-regular, vertex-uniform polytope is dual to the - cuboctahedron. It has 14 vertices and 12 faces. + Return the rhombic dodecahedron. + + The rhombic dodecahedron is a a polytope dual to the cuboctahedron. It + has 14 vertices and 12 faces. For more information see + the :wikipedia:`Rhombic_dodecahedron`. + + .. SEEALSO:: + + :meth:`cuboctahedron` EXAMPLES:: sage: rd = polytopes.rhombic_dodecahedron() - sage: rd.n_vertices() - 14 - sage: rd.n_inequalities() + sage: rd.f_vector() + (1, 14, 24, 12, 1) + + Its faces are 12 quadrilaterals (not all identical):: + + sage: sum(1 for f in rd.faces(2) if len(f.vertices()) == 4) 12 - """ - v = [ [1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1, -1], [-1, 1, 1], - [-1, 1, -1], [-1, -1, 1], [-1, -1, -1], [0, 0, 2], [0, 2, 0], - [2, 0, 0], [0, 0, -2], [0, -2, 0], [-2, 0, 0] ] - return Polyhedron(vertices=v) + Some more computations:: + + sage: p = rd.ehrhart_polynomial() # optional - latte_int + sage: p # optional - latte_int + 16*t^3 + 12*t^2 + 4*t + 1 + sage: [p(i) for i in [1,2,3,4]] # optional - latte_int + [33, 185, 553, 1233] + sage: [len((i*rd).integral_points()) for i in [1,2,3,4]] + [33, 185, 553, 1233] + """ + v = [[2,0,0],[-2,0,0],[0,2,0],[0,-2,0],[0,0,2],[0,0,-2]] + v.extend((itertools.product([1,-1], repeat=3))) + return Polyhedron(vertices=v, base_ring=ZZ) def cuboctahedron(self): """ - An Archimedean solid with 12 vertices and 14 faces. Dual to - the rhombic dodecahedron. + Return the cuboctahedron. + + The cuboctahedron is an Archimedean solid with 12 vertices and 14 faces + dual to the rhombic dodecahedron. It can be defined as the convex hull + of the twelve vertices `(0, \pm 1, \pm 1)`, `(\pm 1, 0, \pm 1)` and + `(\pm 1, \pm 1, 0)`. For more information, see the + :wikipedia:`Cuboctahedron`. + + .. SEEALSO:: + + :meth:`rhombic_dodecahedron` EXAMPLES:: sage: co = polytopes.cuboctahedron() - sage: co.n_vertices() - 12 - sage: co.n_inequalities() - 14 - """ - one = Integer(1) - v = [ [0, -one/2, -one/2], [0, one/2, -one/2], [one/2, -one/2, 0], - [one/2, one/2, 0], [one/2, 0, one/2], [one/2, 0, -one/2], - [0, one/2, one/2], [0, -one/2, one/2], [-one/2, 0, one/2], - [-one/2, one/2, 0], [-one/2, 0, -one/2], [-one/2, -one/2, 0] ] - return Polyhedron(vertices=v) + sage: co.f_vector() + (1, 12, 24, 14, 1) + Its faces are 8 triangles and 6 squares:: + + sage: sum(1 for f in co.faces(2) if len(f.vertices()) == 3) + 8 + sage: sum(1 for f in co.faces(2) if len(f.vertices()) == 4) + 6 - @rename_keyword(deprecation=11634, field='base_ring') - def buckyball(self, base_ring=QQ): + Some more computation:: + + sage: co.volume() + 20/3 + sage: co.ehrhart_polynomial() # optional - latte_int + 20/3*t^3 + 8*t^2 + 10/3*t + 1 + """ + v = [ [ 0, -1, -1], [ 0, 1,-1], [ 1,-1, 0], + [ 1, 1, 0], [ 1, 0, 1], [ 1, 0,-1], + [ 0, 1, 1], [ 0,-1, 1], [-1, 0, 1], + [-1, 1, 0], [-1, 0,-1], [-1,-1, 0] ] + return Polyhedron(vertices=v, base_ring=ZZ) + + def buckyball(self, exact=True, base_ring=None): """ - Also known as the truncated icosahedron, an Archimedean solid. - It has 32 faces and 60 vertices. Rational coordinates are not - exact. + Return the bucky ball. + + The bucky ball, also known as the truncated icosahedron is an Archimedean solid. + It has 32 faces and 60 vertices. + + .. SEEALSO:: + + :meth:`icosahedron` + + INPUT: + + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. + + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: - sage: bb = polytopes.buckyball() - sage: bb.n_vertices() - 60 - sage: bb.n_inequalities() # number of facets - 32 + sage: bb = polytopes.buckyball() # long time - 6secs + sage: bb.f_vector() # long time + (1, 60, 90, 32, 1) + sage: bb.base_ring() # long time + Number Field in sqrt5 with defining polynomial x^2 - 5 + + A much faster implementation using floating point approximations:: + + sage: bb = polytopes.buckyball(exact=False) + sage: bb.f_vector() + (1, 60, 90, 32, 1) sage: bb.base_ring() - Rational Field - """ - # Note: QQ would give some incorrecty subdivided facets - p = self.icosahedron(base_ring=RDF).edge_truncation() - if base_ring==RDF: - return p - # Converting with low precision to save time. - new_ieqs = [[int(1000*x)/QQ(1000) for x in y] for y in p.inequalities()] - return Polyhedron(ieqs=new_ieqs) + Real Double Field + Its faces are 5 regular pentagons and 6 regular hexagons:: - def pentakis_dodecahedron(self): + sage: sum(1 for f in bb.faces(2) if len(f.vertices()) == 5) + 12 + sage: sum(1 for f in bb.faces(2) if len(f.vertices()) == 6) + 20 """ - This face-regular, vertex-uniform polytope is dual to the - truncated icosahedron. It has 60 faces and 32 vertices. + return self.icosahedron(exact=exact, base_ring=base_ring).edge_truncation() + + def pentakis_dodecahedron(self, exact=True, base_ring=None): + """ + Return the pentakis dodecahedron. + + The pentakis dodecahedron (orkisdodecahedron) is a face-regular, + vertex-uniform polytope dual to the truncated icosahedron. It has 60 + faces and 32 vertices. See the :wikipedia:`Pentakis_dodecahedron` for more + information. + + INPUT: + + - ``exact`` -- (boolean, default ``True``) If ``False`` use an + approximate ring for the coordinates. + + - ``base_ring`` -- the ring in which the coordinates will belong to. If + it is not provided and ``exact=True`` it will be a the number field + `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it + will be the real double field. EXAMPLES:: - sage: pd = polytopes.pentakis_dodecahedron() + sage: pd = polytopes.pentakis_dodecahedron() # long time - ~10 sec + sage: pd.n_vertices() # long time + 32 + sage: pd.n_inequalities() # long time + 60 + + A much faster implementation is obtained when setting ``exact=False``:: + + sage: pd = polytopes.pentakis_dodecahedron(exact=False) sage: pd.n_vertices() 32 - sage: pd.n_inequalities() # number of facets + sage: pd.n_inequalities() 60 + + The 60 are triangles:: + + sage: all(len(f.vertices()) == 3 for f in pd.faces(2)) + True """ - return self.buckyball().polar() + return self.buckyball(exact=exact, base_ring=base_ring).polar() def Kirkman_icosahedron(self): """ - A non-uniform icosahedron with interesting properties. - - See [Fetter2012]_ for details. - - OUTPUT: + Return the Kirkman icosahedron. - The Kirkman icosahedron, a 3-dimensional polyhedron - with 20 vertices, 20 faces, and 38 edges. + The Kirkman icosahedron is a 3-polytope with integer coordinates: `(\pm + 9, \pm 6, \pm 6)`, `(\pm 12, \pm 4, 0)`, `(0, \pm 12, \pm 8)`, `(\pm 6, + 0, \pm 12)`. See [Fetter2012]_ for more information. EXAMPLES:: - sage: KI = polytopes.Kirkman_icosahedron() - sage: KI.f_vector() + sage: ki = polytopes.Kirkman_icosahedron() + sage: ki.f_vector() (1, 20, 38, 20, 1) - sage: vertices = KI.vertices() - sage: edges = [[vector(edge[0]),vector(edge[1])] for edge in KI.bounded_edges()] + + sage: ki.volume() + 6528 + + sage: vertices = ki.vertices() + sage: edges = [[vector(edge[0]),vector(edge[1])] for edge in ki.bounded_edges()] sage: edge_lengths = [norm(edge[0]-edge[1]) for edge in edges] sage: union(edge_lengths) [7, 8, 9, 11, 12, 14, 16] """ - vertices = [[-12, -4, 0], [-12, 4, 0], [-9, -6, -6], - [-9, -6, 6], [-9, 6, -6], [-9, 6, 6], [-6, 0, -12], - [-6, 0, 12], [0, -12, -8], [0, -12, 8], [0, 12, -8], - [0, 12, 8], [6, 0, -12], [6, 0, 12], [9, -6, -6], - [9, -6, 6], [9, 6, -6], [9, 6, 6], [12, -4, 0], - [12, 4, 0]] - return Polyhedron(vertices=vertices) - + vertices = [[9, 6, 6], [-9, 6, 6], [9, -6, 6], [9, 6, -6], + [-9, -6, 6], [-9, 6, -6], [9, -6, -6], [-9, -6, -6], + [12, 4, 0], [-12, 4, 0], [12, -4, 0], [-12, -4, 0], + [0, 12, 8], [0, -12, 8], [0, 12, -8], [0, -12, -8], + [6, 0, 12], [-6, 0, 12], [6, 0, -12], [-6, 0, -12]] + return Polyhedron(vertices=vertices, base_ring=ZZ) def twenty_four_cell(self): """ Return the standard 24-cell polytope. - OUTPUT: - - A Polyhedron object of the 4-dimensional 24-cell, a regular - polytope. The coordinates of this polytope are exact. + The 24-cell polyhedron (also called icositetrachoron or octaplex) is a + regular polyhedron in 4-dimension. For more information see + the :wikipedia:`24-cell`. EXAMPLES:: sage: p24 = polytopes.twenty_four_cell() + sage: p24.f_vector() + (1, 24, 96, 96, 24, 1) sage: v = next(p24.vertex_generator()) sage: for adj in v.neighbors(): print adj A vertex at (-1/2, -1/2, -1/2, 1/2) @@ -467,137 +706,157 @@ def twenty_four_cell(self): A vertex at (0, 0, -1, 0) A vertex at (0, 0, 0, -1) A vertex at (1/2, -1/2, -1/2, -1/2) + + sage: p24.volume() + 2 """ - verts = [] - q12 = QQ(1)/2 - base = [q12,q12,q12,q12] - for i in range(2): - for j in range(2): - for k in range(2): - for l in range(2): - verts.append([x for x in base]) - base[3] = base[3]*(-1) - base[2] = base[2]*(-1) - base[1] = base[1]*(-1) - base[0] = base[0]*(-1) - verts = verts + Permutations([0,0,0,1]).list() - verts = verts + Permutations([0,0,0,-1]).list() + q12 = QQ((1,2)) + verts = list(itertools.product([q12,-q12], repeat=4)) + B4 = (ZZ**4).basis() + verts.extend(v for v in B4) + verts.extend(-v for v in B4) return Polyhedron(vertices=verts) - - def six_hundred_cell(self): + def six_hundred_cell(self, exact=False): """ Return the standard 600-cell polytope. - OUTPUT: + The 600-cell is a 4-dimensional regular polytope. In many ways this is + an analogue of the icosahedron. + + .. WARNING:: + + The coordinates are not exact. The computation with exact + coordinates takes a huge amount of time. + + INPUT: - A Polyhedron object of the 4-dimensional 600-cell, a regular - polytope. In many ways this is an analogue of the - icosahedron. The coordinates of this polytope are rational - approximations of the true coordinates of the 600-cell, some - of which involve the (irrational) golden ratio. + - ``exact`` - (boolean, default ``False``) if ``True`` use exact + coordinates instead of floating point approximations EXAMPLES:: - sage: p600 = polytopes.six_hundred_cell() # not tested - very long time - sage: len(list(p600.bounded_edges())) # not tested - very long time + sage: p600 = polytopes.six_hundred_cell() + sage: p600 + A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 120 vertices + sage: p600.f_vector() + (1, 120, 720, 1200, 600, 1) + + Computation with exact coordinates is currently too long to be useful:: + + sage: p600 = polytopes.six_hundred_cell(exact=True) # not tested - very long time + sage: len(list(p600.bounded_edges())) # not tested - very long time 120 """ - verts = [] - q12 = QQ(1)/2 - base = [q12,q12,q12,q12] - for i in range(2): - for j in range(2): - for k in range(2): - for l in range(2): - verts.append([x for x in base]) - base[3] = base[3]*(-1) - base[2] = base[2]*(-1) - base[1] = base[1]*(-1) - base[0] = base[0]*(-1) - verts += Permutations([0,0,0,1]).list() - verts += Permutations([0,0,0,-1]).list() - g = QQ(1618033)/1000000 # Golden ratio approximation - verts = verts + [i([q12,g/2,1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([q12,g/2,-1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([q12,-g/2,1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([q12,-g/2,-1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([-q12,g/2,1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([-q12,g/2,-1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([-q12,-g/2,1/(g*2),0]) for i in AlternatingGroup(4)] - verts = verts + [i([-q12,-g/2,-1/(g*2),0]) for i in AlternatingGroup(4)] - return Polyhedron(vertices=verts) + q12 = QQ((1,2)) + verts = [[s1*q12, s2*q12, s3*q12, s4*q12] for s1,s2,s3,s4 in itertools.product([1,-1], repeat=4)] + V = ZZ**4 + verts.extend(V.basis()) + verts.extend(-v for v in V.basis()) + + if exact: + from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') + sqrt5 = K.gen() + g = (1 + sqrt5) / 2 + base_ring = K + else: + g = (1 + RDF(5).sqrt()) / 2 + base_ring = RDF + pts = [[s1 * q12, s2*g/2, s3/(2*g), 0] for (s1,s2,s3) in itertools.product([1,-1], repeat=3)] + for p in AlternatingGroup(4): + verts.extend(p(x) for x in pts) + return Polyhedron(vertices=verts, base_ring=base_ring) - @rename_keyword(deprecation=11634, field='base_ring') - def cyclic_polytope(self, dim_n, points_n, base_ring=QQ): + @rename_keyword(deprecation=18213, points_n='n', dim_n='dim') + def cyclic_polytope(self, dim, n, base_ring=QQ): """ Return a cyclic polytope. + A cyclic polytope of dimension ``dim`` with ``n`` vertices is the convex + hull of the points ``(t,t^2,...,t^dim)`` with `t \in \{0,1,...,n-1\}` . + For more information, see the :wikipedia:`Cyclic_polytope`. + INPUT: - - ``dim_n`` -- positive integer. the dimension of the polytope. + - ``dim`` -- positive integer. the dimension of the polytope. - - ``points_n`` -- positive integer. the number of vertices. + - ``n`` -- positive integer. the number of vertices. - ``base_ring`` -- either ``QQ`` (default) or ``RDF``. OUTPUT: - A cyclic polytope of dim_n with points_n vertices on the - moment curve ``(t,t^2,...,t^n)``, as Polyhedron object. - EXAMPLES:: sage: c = polytopes.cyclic_polytope(4,10) - sage: c.n_inequalities() - 35 + sage: c.f_vector() + (1, 10, 45, 70, 35, 1) """ - verts = [[t**i for i in range(1,dim_n+1)] for t in range(points_n)] + verts = [[t**i for i in range(1,dim+1)] for t in range(n)] return Polyhedron(vertices=verts, base_ring=base_ring) - - def hypersimplex(self, dim_n, k, project = True): + @rename_keyword(deprecation=18213, dim_n='dim') + def hypersimplex(self, dim, k, project=False): """ - The hypersimplex in dimension dim_n with d choose k vertices, - projected into (dim_n - 1) dimensions. + Return the hypersimplex in dimension ``dim`` and parameter ``k``. - INPUT: + The hypersimplex `\Delta_{d,k}` is the convex hull of the vertices made + of `k` ones and `d-k` zeros. It lies in the `d-1` hyperplane of vectors + of sum `k`. If you want a projected version to `\RR^{d-1}` (with + floating point coordinates) then set ``project=True`` in the options. - - ``n`` -- the numbers ``(1,...,n)`` are permuted + .. SEEALSO:: - - ``project`` -- If ``False``, the polyhedron is left in - dimension ``n``. + :meth:`simplex` - OUTPUT: + INPUT: + + - ``dim`` -- the dimension - A Polyhedron object representing the hypersimplex. + - ``n`` -- the numbers ``(1,...,n)`` are permuted + + - ``project`` -- (boolean, default ``False``) if ``True``, the polytope + is (isometrically) projected to a vector space of dimension ``dim-1``. + This operation turns the coordinates into floating point + approximations. EXAMPLES:: - sage: h_4_2 = polytopes.hypersimplex(4,2) # combinatorially equivalent to octahedron - sage: h_4_2.n_vertices() - 6 - sage: h_4_2.n_inequalities() - 8 - """ - vert0 = [0]*(dim_n-k) + [1]*k - verts = Permutations(vert0).list() - if project: - verts = [Polytopes.project_1(x) for x in verts] + sage: h_4_2 = polytopes.hypersimplex(4, 2) + sage: h_4_2 + A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 6 vertices + sage: h_4_2.f_vector() + (1, 6, 12, 8, 1) + sage: h_4_2.ehrhart_polynomial() # optional - latte_int + 2/3*t^3 + 2*t^2 + 7/3*t + 1 + + sage: h_7_3 = polytopes.hypersimplex(7, 3, project=True) + sage: h_7_3 + A 6-dimensional polyhedron in RDF^6 defined as the convex hull of 35 vertices + sage: h_7_3.f_vector() + (1, 35, 210, 350, 245, 84, 14, 1) + """ + verts = Permutations([0]*(dim-k) + [1]*k).list() + if project: verts = project_points(*verts) return Polyhedron(vertices=verts) - - def permutahedron(self, n, project = True): + def permutahedron(self, n, project=False): """ - The standard permutahedron of (1,...,n) projected into n-1 - dimensions. + Return the standard permutahedron of (1,...,n) + + The premutahedron (or permutohedron) is the convex hull of the + permutations of `\{1,\ldots,n\}` seen as vectors. INPUT: - - ``n`` -- the numbers ``(1,...,n)`` are permuted + - ``n`` -- integer - - ``project`` -- If ``False`` the polyhedron is left in dimension ``n``. + - ``project`` -- (boolean, default ``False``) if ``True``, the polytope + is (isometrically) projected to a vector space of dimension ``dim-1``. + This operation turns the coordinates into floating point + approximations. OUTPUT: @@ -605,110 +864,137 @@ def permutahedron(self, n, project = True): EXAMPLES:: + sage: perm4 = polytopes.permutahedron(4) sage: perm4 - A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices - sage: polytopes.permutahedron(5).plot() # long time + A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 24 vertices + sage: perm4.is_lattice_polytope() + True + sage: perm4.ehrhart_polynomial() # optional - latte_int + 16*t^3 + 15*t^2 + 6*t + 1 + + sage: perm4 = polytopes.permutahedron(4, project=True) + sage: perm4 + A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices + sage: perm4.plot() Graphics3d Object """ - verts = range(1,n+1) - verts = Permutations(verts).list() - if project: - verts = [Polytopes.project_1(x) for x in verts] - p = Polyhedron(vertices=verts) - return p - + verts = list(itertools.permutations(range(1,n+1))) + if project: verts = project_points(*verts) + return Polyhedron(vertices=verts) - def n_cube(self, dim_n): + def hypercube(self, dim): """ - Return a cube in the given dimension - - INPUT: + Return a hypercube in the given dimension - - ``dim_n`` -- integer. The dimension of the cube. + The `d` dimensional hypercube is the convex hull of the points `(\pm 1, + \pm 1, \ldots, \pm 1)` in `\RR^d`. For more information see + the :wikipedia:`Hypercube`. - OUTPUT: + INPUT: - A Polyhedron object of the ``dim_n``-dimensional cube, with - exact coordinates. + - ``dim`` -- integer. The dimension of the cube. EXAMPLES:: - sage: four_cube = polytopes.n_cube(4) + sage: four_cube = polytopes.hypercube(4) sage: four_cube.is_simple() True + sage: four_cube.base_ring() + Integer Ring + sage: four_cube.volume() + 16 + sage: four_cube.ehrhart_polynomial() # optional - latte_int + 16*t^4 + 32*t^3 + 24*t^2 + 8*t + 1 """ - if dim_n == 1: - return Polyhedron(vertices = [[1],[-1]]) + return Polyhedron(vertices = list(itertools.product([1,-1], repeat=dim))) - pre_cube = polytopes.n_cube(dim_n-1) - vertices = []; - for pre_v in pre_cube.vertex_generator(): - vertices.append( [ 1] + [v for v in pre_v] ); - vertices.append( [-1] + [v for v in pre_v] ); - return Polyhedron(vertices = vertices) + def cube(self): + r""" + Return the cube. + The cube is the Platonic solid that is obtained as the convex hull of + the points `(\pm 1, \pm 1, \pm 1)`. It generalizes into several + dimension into hypercubes. - def cross_polytope(self, dim_n): + .. SEEALSO:: + + :meth:`hypercube` + + EXAMPLES:: + + sage: c = polytopes.cube() + sage: c + A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices + sage: c.f_vector() + (1, 8, 12, 6, 1) + sage: c.volume() + 8 + sage: c.plot() + Graphics3d Object """ - Return a cross-polytope in dimension ``dim_n``. These are - the generalization of the octahedron. + return self.hypercube(3) - INPUT: + n_cube = deprecated_function_alias(18213, hypercube) - - ``dim_n`` -- integer. The dimension of the cross-polytope. + def cross_polytope(self, dim): + """ + Return a cross-polytope in dimension ``dim``. - OUTPUT: + A cross-polytope is a higher dimensional generalization of the + octahedron. It is the convex hull of the `2d` points `(\pm 1, 0, \ldots, + 0)`, `(0, \pm 1, \ldots, 0)`, \ldots, `(0, 0, \ldots, \pm 1)`. + See the :wikipedia:`Cross-polytope` for more information. - A Polyhedron object of the ``dim_n``-dimensional cross-polytope, - with exact coordinates. + INPUT: + + - ``dim`` -- integer. The dimension of the cross-polytope. EXAMPLES:: sage: four_cross = polytopes.cross_polytope(4) + sage: four_cross.f_vector() + (1, 8, 24, 32, 16, 1) sage: four_cross.is_simple() False - sage: four_cross.n_vertices() - 8 """ - verts = Permutations([0 for i in range(dim_n-1)] + [1]).list() - verts += Permutations([0 for i in range(dim_n-1)] + [-1]).list() + verts = list((ZZ**dim).basis()) + verts.extend([-v for v in verts]) return Polyhedron(vertices=verts) - def parallelotope(self, generators): r""" Return the parallelotope spanned by the generators. - INPUT: - - - ``generators`` -- an iterable of anything convertible to vector - (for example, a list of vectors) such that the vectors all - have the same dimension. + The parallelotope is the multi-dimensional generalization of a + parallelogram (2 generators) and a parallelepiped (3 generators). - OUTPUT: + INPUT: - The parallelotope. This is the multi-dimensional - generalization of a parallelogram (2 generators) and a - parallelepiped (3 generators). + - ``generators`` -- a list vector of vectors of same dimension EXAMPLES:: sage: polytopes.parallelotope([ (1,0), (0,1) ]) - A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]) - A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 16 vertices - """ - try: - generators = [ vector(QQ,v) for v in generators ] - base_ring = QQ - except TypeError: - generators = [ vector(RDF,v) for v in generators ] - base_ring = RDF - - from sage.combinat.combination import Combinations - par = [ 0*generators[0] ] - par += [ sum(c) for c in Combinations(generators) if c!=[] ] - return Polyhedron(vertices=par, base_ring=base_ring) + A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 16 vertices + + sage: K = QuadraticField(2, 'sqrt2') + sage: sqrt2 = K.gen() + sage: polytopes.parallelotope([ (1,sqrt2), (1,-1) ]) + A 2-dimensional polyhedron in (Number Field in sqrt2 with defining + polynomial x^2 - 2)^2 defined as the convex hull of 4 vertices + """ + from sage.modules.free_module_element import vector + from sage.structure.sequence import Sequence + generators = map(vector,generators) + V = Sequence(generators).universe() + R = V.base_ring() + + from itertools import combinations + par = [ V.zero() ] + par.extend(sum(c) for k in range(1,len(generators)+1) for c in combinations(generators,k)) + return Polyhedron(vertices=par, base_ring=R) polytopes = Polytopes() From 2ddcdefe27f54a99c4fa154fd075229019801e90 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 16 Apr 2015 16:32:23 +0200 Subject: [PATCH 324/665] Trac 18213: fix doctests --- src/sage/geometry/polyhedron/base.py | 139 +++++++++--------- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- src/sage/geometry/polyhedron/face.py | 8 +- src/sage/geometry/polyhedron/plot.py | 38 ++--- .../geometry/polyhedron/representation.py | 22 +-- 5 files changed, 108 insertions(+), 101 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index d001c824b9d..37b7f20b771 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -63,7 +63,7 @@ def is_Polyhedron(X): EXAMPLES:: - sage: p = polytopes.n_cube(2) + sage: p = polytopes.hypercube(2) sage: from sage.geometry.polyhedron.base import is_Polyhedron sage: is_Polyhedron(p) True @@ -481,11 +481,11 @@ def plot(self, EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: point = Polyhedron([[1,1]]) sage: line = Polyhedron([[1,1],[2,1]]) - sage: cube = polytopes.n_cube(3) - sage: hypercube = polytopes.n_cube(4) + sage: cube = polytopes.hypercube(3) + sage: hypercube = polytopes.hypercube(4) By default, the wireframe is rendered in blue and the fill in green:: @@ -609,18 +609,18 @@ def plot(self, sage: type(Polyhedron(ieqs=[(1,)]).plot()) - sage: type(polytopes.n_cube(1).plot()) + sage: type(polytopes.hypercube(1).plot()) - sage: type(polytopes.n_cube(2).plot()) + sage: type(polytopes.hypercube(2).plot()) - sage: type(polytopes.n_cube(3).plot()) + sage: type(polytopes.hypercube(3).plot()) In 4d a projection to 3d is used:: - sage: type(polytopes.n_cube(4).plot()) + sage: type(polytopes.hypercube(4).plot()) - sage: type(polytopes.n_cube(5).plot()) + sage: type(polytopes.hypercube(5).plot()) Traceback (most recent call last): ... NotImplementedError: plotting of 5-dimensional polyhedra not implemented @@ -702,7 +702,7 @@ def show(self, **kwds): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: square.show(point='red') """ self.plot(**kwds).show() @@ -762,7 +762,7 @@ def cdd_Hrepresentation(self): EXAMPLES:: - sage: p = polytopes.n_cube(2) + sage: p = polytopes.hypercube(2) sage: print p.cdd_Hrepresentation() H-representation begin @@ -922,7 +922,7 @@ def Hrepresentation(self, index=None): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: p.Hrepresentation(0) An inequality (0, 0, -1) x + 1 >= 0 sage: p.Hrepresentation(0) == p.Hrepresentation() [0] @@ -941,7 +941,7 @@ def Hrep_generator(self): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: next(p.Hrep_generator()) An inequality (0, 0, -1) x + 1 >= 0 """ @@ -990,9 +990,9 @@ def Vrepresentation(self, index=None): EXAMPLES:: - sage: p = polytopes.n_simplex(4) + sage: p = polytopes.simplex(4, project=True) sage: p.Vrepresentation(0) - A vertex at (-7071/10000, 1633/4000, 7217/25000, 22361/100000) + A vertex at (0.7071067812, 0.4082482905, 0.2886751346, 0.2236067977) sage: p.Vrepresentation(0) == p.Vrepresentation() [0] True """ @@ -1013,7 +1013,7 @@ def n_Vrepresentation(self): EXAMPLES:: - sage: p = polytopes.n_simplex(4) + sage: p = polytopes.simplex(4) sage: p.n_Vrepresentation() 5 sage: p.n_Vrepresentation() == p.n_vertices() + p.n_rays() + p.n_lines() @@ -1563,7 +1563,7 @@ def vertex_adjacency_matrix(self): EXAMPLES:: - sage: polytopes.n_simplex(4).vertex_adjacency_matrix() + sage: polytopes.simplex(4).vertex_adjacency_matrix() [0 1 1 1 1] [1 0 1 1 1] [1 1 0 1 1] @@ -1673,7 +1673,8 @@ def facet_adjacency_matrix(self): EXAMPLES:: - sage: polytopes.n_simplex(4).facet_adjacency_matrix() + sage: s4 = polytopes.simplex(4, project=True) + sage: s4.facet_adjacency_matrix() [0 1 1 1 1] [1 0 1 1 1] [1 1 0 1 1] @@ -1712,10 +1713,10 @@ def incidence_matrix(self): [1 1 0 0 0 0 0 0 0 0 0 0 1 1] sage: v = p.Vrepresentation(0) sage: v - A vertex at (-1/2, -1/2, 0) + A vertex at (-1, -1, 0) sage: h = p.Hrepresentation(2) sage: h - An inequality (1, 1, -1) x + 1 >= 0 + An inequality (1, 1, -1) x + 2 >= 0 sage: h.eval(v) # evaluation (1, 1, -1) * (-1/2, -1/2, 0) + 1 0 sage: h*v # same as h.eval(v) @@ -1769,7 +1770,7 @@ def center(self): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: p = p + vector([1,0,0]) sage: p.center() (1, 0, 0) @@ -1849,7 +1850,7 @@ def radius(self): EXAMPLES:: - sage: p = polytopes.n_cube(4) + sage: p = polytopes.hypercube(4) sage: p.radius() 2 """ @@ -1904,10 +1905,10 @@ def is_simplicial(self): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: p.is_simplicial() False - sage: q = polytopes.n_simplex(5) + sage: q = polytopes.simplex(5, project=True) sage: q.is_simplicial() True sage: p = Polyhedron([[0,0,0],[1,0,0],[0,1,0],[0,0,1]]) @@ -1947,7 +1948,7 @@ def hyperplane_arrangement(self): EXAMPLES:: - sage: p = polytopes.n_cube(2) + sage: p = polytopes.hypercube(2) sage: p.hyperplane_arrangement() Arrangement <-t0 + 1 | -t1 + 1 | t1 + 1 | t0 + 1> """ @@ -2043,7 +2044,7 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s EXAMPLES:: - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.hypercube(3) sage: triangulation = cube.triangulate( ... engine='internal') # to make doctest independent of TOPCOM sage: triangulation @@ -2091,12 +2092,12 @@ def Minkowski_sum(self, other): EXAMPLES:: - sage: X = polytopes.n_cube(3) + sage: X = polytopes.hypercube(3) sage: Y = Polyhedron(vertices=[(0,0,0), (0,0,1/2), (0,1/2,0), (1/2,0,0)]) sage: X+Y A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 13 vertices - sage: four_cube = polytopes.n_cube(4) + sage: four_cube = polytopes.hypercube(4) sage: four_simplex = Polyhedron(vertices = [[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]) sage: four_cube + four_simplex A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 36 vertices @@ -2160,7 +2161,7 @@ def Minkowski_difference(self, other): EXAMPLES:: - sage: X = polytopes.n_cube(3) + sage: X = polytopes.hypercube(3) sage: Y = Polyhedron(vertices=[(0,0,0), (0,0,1), (0,1,0), (1,0,0)]) / 2 sage: (X+Y)-Y == X True @@ -2179,7 +2180,7 @@ def Minkowski_difference(self, other): Minus sign is really an alias for :meth:`Minkowski_difference` :: - sage: four_cube = polytopes.n_cube(4) + sage: four_cube = polytopes.hypercube(4) sage: four_simplex = Polyhedron(vertices = [[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]) sage: four_cube - four_simplex A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 16 vertices @@ -2195,7 +2196,7 @@ def Minkowski_difference(self, other): TESTS:: - sage: X = polytopes.n_cube(2) + sage: X = polytopes.hypercube(2) sage: Y = Polyhedron(vertices=[(1,1)]) sage: (X-Y).Vrepresentation() (A vertex at (0, -2), A vertex at (0, 0), A vertex at (-2, 0), A vertex at (-2, -2)) @@ -2248,7 +2249,7 @@ def __sub__(self, other): EXAMPLES:: - sage: X = polytopes.n_cube(2) + sage: X = polytopes.hypercube(2) sage: v = vector([1,1]) sage: (X - v/2).Vrepresentation() (A vertex at (-3/2, -3/2), A vertex at (-3/2, 1/2), @@ -2280,7 +2281,7 @@ def is_Minkowski_summand(self, Y): EXAMPLES:: - sage: A = polytopes.n_cube(2) + sage: A = polytopes.hypercube(2) sage: B = Polyhedron(vertices=[(0,1), (1/2,1)]) sage: C = Polyhedron(vertices=[(1,1)]) sage: A.is_Minkowski_summand(B) @@ -2481,7 +2482,7 @@ def __neg__(self): EXAMPLES:: - sage: t = polytopes.n_simplex(3,project=False); t.vertices() + sage: t = polytopes.simplex(3,project=False); t.vertices() (A vertex at (0, 0, 0, 1), A vertex at (0, 0, 1, 0), A vertex at (0, 1, 0, 0), A vertex at (1, 0, 0, 0)) sage: neg_ = -t @@ -2530,7 +2531,7 @@ def convex_hull(self, other): EXAMPLES:: - sage: a_simplex = polytopes.n_simplex(3) + sage: a_simplex = polytopes.simplex(3, project=True) sage: verts = a_simplex.vertices() sage: verts = [[x[0]*3/5+x[1]*4/5, -x[0]*4/5+x[1]*3/5, x[2]] for x in verts] sage: another_simplex = Polyhedron(vertices = verts) @@ -2562,7 +2563,7 @@ def intersection(self, other): EXAMPLES:: - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.hypercube(3) sage: oct = polytopes.cross_polytope(3) sage: cube.intersection(oct*2) A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 12 vertices @@ -2613,7 +2614,7 @@ def edge_truncation(self, cut_frac = Integer(1)/3): EXAMPLES:: - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.hypercube(3) sage: trunc_cube = cube.edge_truncation() sage: trunc_cube.n_vertices() 24 @@ -2653,7 +2654,7 @@ def _make_polyhedron_face(self, Vindices, Hindices): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: square._make_polyhedron_face((0,2), (1,)) <0,2> """ @@ -2722,7 +2723,7 @@ def face_lattice(self): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: square.face_lattice() Finite poset containing 10 elements with distinguished linear extension sage: list(_) @@ -2763,7 +2764,7 @@ def face_lattice(self): sage: c5_20_fl = c5_20.face_lattice() # long time sage: [len(x) for x in c5_20_fl.level_sets()] # long time [1, 20, 190, 580, 680, 272, 1] - sage: polytopes.n_cube(2).face_lattice().plot() + sage: polytopes.hypercube(2).face_lattice().plot() Graphics object consisting of 27 graphics primitives sage: level_sets = polytopes.cross_polytope(2).face_lattice().level_sets() sage: print level_sets[0], level_sets[-1] @@ -2862,7 +2863,7 @@ def faces(self, face_dimension): Here we find the vertex and face indices of the eight three-dimensional facets of the four-dimensional hypercube:: - sage: p = polytopes.n_cube(4) + sage: p = polytopes.hypercube(4) sage: p.faces(3) (<0,1,2,3,4,5,6,7>, <0,1,2,3,8,9,10,11>, <0,1,4,5,8,9,12,13>, <0,2,4,6,8,10,12,14>, <2,3,6,7,10,11,14,15>, <8,9,10,11,12,13,14,15>, @@ -2947,11 +2948,11 @@ def vertex_graph(self): EXAMPLES:: - sage: g3 = polytopes.n_cube(3).vertex_graph(); g3 + sage: g3 = polytopes.hypercube(3).vertex_graph(); g3 Graph on 8 vertices sage: g3.automorphism_group().cardinality() 48 - sage: s4 = polytopes.n_simplex(4).vertex_graph(); s4 + sage: s4 = polytopes.simplex(4).vertex_graph(); s4 Graph on 5 vertices sage: s4.is_eulerian() True @@ -3046,7 +3047,7 @@ def polar(self): sage: p.polar() A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.hypercube(3) sage: octahedron = polytopes.cross_polytope(3) sage: cube_dual = cube.polar() sage: octahedron == cube_dual @@ -3064,7 +3065,7 @@ def pyramid(self): EXAMPLES:: - sage: square = polytopes.n_cube(2); square + sage: square = polytopes.hypercube(2); square A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices sage: egyptian_pyramid = square.pyramid(); egyptian_pyramid A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 5 vertices @@ -3123,7 +3124,7 @@ def prism(self): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: cube = square.prism() sage: cube A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices @@ -3154,7 +3155,7 @@ def projection(self): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: proj = p.projection() sage: proj The projection of a polyhedron into 3 dimensions @@ -3169,7 +3170,7 @@ def render_solid(self, **kwds): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: p_solid = p.render_solid(opacity = .7) sage: type(p_solid) @@ -3230,7 +3231,7 @@ def schlegel_projection(self, projection_dir=None, height=1.1): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: sch_proj = p.schlegel_projection() sage: schlegel_edge_indices = sch_proj.lines sage: schlegel_edges = [sch_proj.coordinates_of(x) for x in schlegel_edge_indices] @@ -3257,9 +3258,9 @@ def _volume_lrs(self, verbose=False): EXAMPLES:: - sage: polytopes.n_cube(3)._volume_lrs() #optional - lrs + sage: polytopes.hypercube(3)._volume_lrs() #optional - lrs 8.0 - sage: (polytopes.n_cube(3)*2)._volume_lrs() #optional - lrs + sage: (polytopes.hypercube(3)*2)._volume_lrs() #optional - lrs 64.0 sage: polytopes.twenty_four_cell()._volume_lrs() #optional - lrs 2.0 @@ -3303,6 +3304,8 @@ def volume(self, engine='auto', **kwds): """ Return the volume of the polytope. + INPUT: + - ``engine`` -- string. The backend to use. Allowed values are: * ``'auto'`` (default): see :meth:`triangulate`. @@ -3319,23 +3322,27 @@ def volume(self, engine='auto', **kwds): EXAMPLES:: - sage: polytopes.n_cube(3).volume() + sage: polytopes.hypercube(3).volume() 8 - sage: (polytopes.n_cube(3)*2).volume() + sage: (polytopes.hypercube(3)*2).volume() 64 sage: polytopes.twenty_four_cell().volume() 2 - sage: polytopes.regular_polygon(5, base_ring=RDF).volume() - 2.37764129... - sage: P5 = polytopes.regular_polygon(5, base_ring=QQ) - sage: P5.volume() # rational approximation - 143675742936485206271005807482349119225365261915467953640852591/60427846494832899490396166935397049960830782710733164218307960 - sage: _.n() - 2.37764129... + If the base ring is exact, the answer is exact:: + + sage: P5 = polytopes.regular_polygon(5) + sage: P5.volume() + 2.377641290737884? + + sage: polytopes.icosahedron().volume() + 5/12*sqrt5 + 5/4 + sage: numerical_approx(_) + 2.18169499062491 - Volume of the same polytope, using the optional package lrs:: + Volume of the same polytopes, using the optional package lrs:: + sage: P5 = polytopes.regular_polygon(5, base_ring=RDF) sage: P5.volume(engine='lrs') #optional - lrs 2.37764129... """ @@ -3545,9 +3552,9 @@ def is_simplex(self): sage: Polyhedron([(0,0,0), (1,0,0), (0,1,0)]).is_simplex() True - sage: polytopes.n_simplex(3).is_simplex() + sage: polytopes.simplex(3).is_simplex() True - sage: polytopes.n_cube(3).is_simplex() + sage: polytopes.hypercube(3).is_simplex() False """ return self.is_compact() and (self.dim()+1==self.n_vertices()) @@ -3724,8 +3731,8 @@ def bounding_box(self, integral=False): ((1/3, 1/3), (2/3, 2/3)) sage: Polyhedron([ (1/3,2/3), (2/3, 1/3) ]).bounding_box(integral=True) ((0, 0), (1, 1)) - sage: polytopes.buckyball().bounding_box() - ((-1059/1309, -1059/1309, -1059/1309), (1059/1309, 1059/1309, 1059/1309)) + sage: polytopes.buckyball(exact=False).bounding_box() + ((-0.8090169944, -0.8090169944, -0.8090169944), (0.8090169944, 0.8090169944, 0.8090169944)) """ box_min = [] box_max = [] @@ -4176,7 +4183,7 @@ def is_full_dimensional(self): EXAMPLES:: - sage: polytopes.n_cube(3).is_full_dimensional() + sage: polytopes.hypercube(3).is_full_dimensional() True sage: Polyhedron(vertices=[(1,2,3)], rays=[(1,0,0)]).is_full_dimensional() False diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 125039f89df..64343e0b035 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -475,7 +475,7 @@ def find_translation(self, translated_polyhedron): EXAMPLES:: - sage: X = polytopes.n_cube(3) + sage: X = polytopes.cube() sage: X.find_translation(X + vector([2,3,5])) (2, 3, 5) sage: X.find_translation(2*X) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 61ed02770cd..8446f5df7bb 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -248,7 +248,7 @@ def __cmp__(self, other): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: f = square.faces(1) sage: matrix(4,4, lambda i,j: cmp(f[i], f[j])) [ 0 -1 -1 -1] @@ -284,7 +284,7 @@ def ambient_Hrepresentation(self, index=None): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: for face in square.face_lattice(): ... print face.ambient_Hrepresentation() (An inequality (1, 0) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, @@ -325,7 +325,7 @@ def ambient_Vrepresentation(self, index=None): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: for fl in square.face_lattice(): ... print fl.ambient_Vrepresentation() ... @@ -444,7 +444,7 @@ def _repr_(self): EXAMPLES:: - sage: square = polytopes.n_cube(2) + sage: square = polytopes.hypercube(2) sage: a_face = list( square.face_lattice() )[8] sage: a_face.__repr__() '<1,3>' diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index ee838d9ed97..9ef0ef3acb4 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -143,7 +143,7 @@ def render_4d(polyhedron, point_opts={}, line_opts={}, polygon_opts={}, projecti TESTS:: sage: from sage.geometry.polyhedron.plot import render_4d - sage: p = polytopes.n_cube(4) + sage: p = polytopes.hypercube(4) sage: q = render_4d(p) doctest:...: DeprecationWarning: use Polyhedron.schlegel_projection instead See http://trac.sagemath.org/16625 for details. @@ -289,7 +289,7 @@ class ProjectionFuncStereographic(): EXAMPLES:: sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic - sage: cube = polytopes.n_cube(3).vertices() + sage: cube = polytopes.hypercube(3).vertices() sage: proj = ProjectionFuncStereographic([1.2, 3.4, 5.6]) sage: ppoints = [proj(vector(x)) for x in cube] sage: ppoints[0] @@ -461,7 +461,7 @@ def __init__(self, polyhedron, proj=projection_func_identity): EXAMPLES:: - sage: p = polytopes.icosahedron() + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(p) The projection of a polyhedron into 3 dimensions @@ -511,7 +511,7 @@ def _repr_(self): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: from sage.geometry.polyhedron.plot import Projection sage: proj = Projection(p) sage: print proj._repr_() @@ -528,13 +528,13 @@ def __call__(self, proj=projection_func_identity): EXAMPLES:: - sage: p = polytopes.icosahedron() + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: pproj = Projection(p) sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic sage: pproj_stereo = pproj.__call__(proj = ProjectionFuncStereographic([1,2,3])) sage: pproj_stereo.polygons[0] - [10, 4, 6] + [10, 1, 4] """ self.transformed_coords = \ Sequence([proj(p) for p in self.coords]) @@ -548,7 +548,7 @@ def identity(self): EXAMPLES:: - sage: p = polytopes.icosahedron() + sage: p = polytopes.icosahedron(exact=False) sage: from sage.geometry.polyhedron.plot import Projection sage: pproj = Projection(p) sage: ppid = pproj.identity() @@ -609,7 +609,7 @@ def schlegel(self, projection_direction=None, height=1.1): EXAMPLES:: - sage: cube4 = polytopes.n_cube(4) + sage: cube4 = polytopes.hypercube(4) sage: from sage.geometry.polyhedron.plot import Projection sage: Projection(cube4).schlegel([1,0,0,0]) The projection of a polyhedron into 3 dimensions @@ -637,7 +637,7 @@ def coord_index_of(self, v): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: proj = p.projection() sage: proj.coord_index_of(vector((1,1,1))) 7 @@ -656,7 +656,7 @@ def coord_indices_of(self, v_list): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: proj = p.projection() sage: proj.coord_indices_of([vector((1,1,1)),vector((1,-1,1))]) [7, 5] @@ -670,9 +670,9 @@ def coordinates_of(self, coord_index_list): EXAMPLES:: - sage: p = polytopes.n_simplex(4).projection() + sage: p = polytopes.simplex(4, project=True).projection() sage: p.coordinates_of([1]) - [[0, -81649/100000, 7217/25000, 22361/100000]] + [[-0.7071067812, 0.4082482905, 0.2886751346, 0.2236067977]] """ return [self.transformed_coords[i] for i in coord_index_list] @@ -686,7 +686,7 @@ def _init_dimension(self): TESTS:: sage: from sage.geometry.polyhedron.plot import Projection, render_2d - sage: p = polytopes.n_simplex(2).projection() + sage: p = polytopes.simplex(2, project=True).projection() sage: test = p._init_dimension() sage: p.plot.__doc__ == p.render_2d.__doc__ True @@ -716,7 +716,7 @@ def show(self, *args, **kwds): EXAMPLE:: - sage: P8 = polytopes.n_cube(4) + sage: P8 = polytopes.hypercube(4) sage: P8.schlegel_projection([2,5,11,17]).show() doctest:...: DeprecationWarning: use Projection.plot instead See http://trac.sagemath.org/16625 for details. @@ -778,7 +778,7 @@ def _init_points(self, polyhedron): TESTS:: - sage: p = polytopes.n_cube(2) + sage: p = polytopes.hypercube(2) sage: pp = p.projection() sage: del pp.points sage: pp.points = Sequence([]) @@ -977,7 +977,7 @@ def render_points_1d(self, **kwds): EXAMPLES:: - sage: cube1 = polytopes.n_cube(1) + sage: cube1 = polytopes.hypercube(1) sage: proj = cube1.projection() sage: points = proj.render_points_1d() sage: points._objects @@ -1000,7 +1000,7 @@ def render_line_1d(self, **kwds): EXAMPLES:: - sage: outline = polytopes.n_cube(1).projection().render_line_1d() + sage: outline = polytopes.hypercube(1).projection().render_line_1d() sage: outline._objects[0] Line defined by 2 points """ @@ -1087,7 +1087,7 @@ def render_wireframe_3d(self, **kwds): EXAMPLES:: - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.hypercube(3) sage: cube_proj = cube.projection() sage: wire = cube_proj.render_wireframe_3d() sage: print wire.tachyon().split('\n')[77] # for testing @@ -1108,7 +1108,7 @@ def render_solid_3d(self, **kwds): EXAMPLES:: - sage: p = polytopes.n_cube(3).projection() + sage: p = polytopes.hypercube(3).projection() sage: p_solid = p.render_solid_3d(opacity = .7) sage: type(p_solid) diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index dce79f5a090..cdf0b9a0e92 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -144,20 +144,20 @@ def vector(self, base_ring=None): sage: s = polytopes.cuboctahedron() sage: v = next(s.vertex_generator()) sage: v - A vertex at (-1/2, -1/2, 0) + A vertex at (-1, -1, 0) sage: v.vector() - (-1/2, -1/2, 0) + (-1, -1, 0) sage: v() - (-1/2, -1/2, 0) + (-1, -1, 0) sage: type(v()) - + Conversion to a different base ring can be forced with the optional argument:: sage: v.vector(RDF) - (-0.5, -0.5, 0.0) + (-1.0, -1.0, 0.0) sage: vector(RDF, v) - (-0.5, -0.5, 0.0) + (-1.0, -1.0, 0.0) """ if (base_ring is None) or (base_ring is self._base_ring): return self._vector @@ -630,7 +630,7 @@ def contains(self, Vobj): sage: i1 = next(p.inequality_generator()) sage: [i1.contains(q) for q in p.vertex_generator()] [True, True, True, True, True, True] - sage: p2 = 3*polytopes.n_cube(3) + sage: p2 = 3*polytopes.hypercube(3) sage: [i1.contains(q) for q in p2.vertex_generator()] [True, False, False, False, True, True, True, False] """ @@ -657,7 +657,7 @@ def interior_contains(self, Vobj): sage: i1 = next(p.inequality_generator()) sage: [i1.interior_contains(q) for q in p.vertex_generator()] [False, True, True, False, False, True] - sage: p2 = 3*polytopes.n_cube(3) + sage: p2 = 3*polytopes.hypercube(3) sage: [i1.interior_contains(q) for q in p2.vertex_generator()] [True, False, False, False, True, True, True, False] @@ -965,7 +965,7 @@ def is_incident(self, Hobj): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: h1 = next(p.inequality_generator()) sage: h1 An inequality (0, 0, -1) x + 1 >= 0 @@ -983,7 +983,7 @@ def __mul__(self, Hobj): TESTS:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: h1 = next(p.inequality_generator()) sage: v1 = next(p.vertex_generator()) sage: v1.__mul__(h1) @@ -1090,7 +1090,7 @@ def evaluated_on(self, Hobj): EXAMPLES:: - sage: p = polytopes.n_cube(3) + sage: p = polytopes.hypercube(3) sage: v = next(p.vertex_generator()) sage: h = next(p.inequality_generator()) sage: v From 524f00ea3d1d3734a9915cd6052d0bf677fdb6e3 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 16 Apr 2015 17:21:47 +0200 Subject: [PATCH 325/665] Trac 18213: Seealsos --- src/sage/geometry/polyhedron/library.py | 5 +++++ src/sage/matrix/matrix2.pyx | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 02a18d39c45..18759e8393d 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -204,6 +204,11 @@ def Birkhoff_polytope(self, n): - ``n`` -- a positive integer giving the size of the permutation matrices. + .. SEEALSO:: + + :meth:`sage.matrix.matrix2.Matrix.as_sum_of_permutations` -- return + the current matrix as a sum of permutation matrices + EXAMPLES:: sage: b3 = polytopes.Birkhoff_polytope(3) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index eef68724811..50e162809b8 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8268,10 +8268,13 @@ cdef class Matrix(matrix1.Matrix): This function, given a bistochastic matrix, returns the corresponding decomposition. - .. SEEALSO: + .. SEEALSO:: + + - :func:`bistochastic_as_sum_of_permutations + ` + -- for more information on this method. - - :meth:`bistochastic_as_sum_of_permutations ` - -- for more information on this method. + - :meth:`~sage.geometry.polyhedron.library.Polytopes.Birkhoff_polytope` EXAMPLE: From 6afd117df805ce5b42c8019069824ed0cd0d277f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 17 Apr 2015 14:06:28 +0200 Subject: [PATCH 326/665] trac #18185: broken import --- src/sage/coding/binary_code.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 2d3618e0a06..80b64c4fe1a 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -954,7 +954,7 @@ cdef class BinaryCode: 10011001 01101001 """ - from sage.graphs.generic_graph_pyx import binary + from sage.graphs.generic_graph_pyx import int_to_binary_string cdef int ui cdef int i s = '' @@ -964,13 +964,13 @@ cdef class BinaryCode: s += "\nradix:" + str(self.radix) s += "\nbasis:\n" for i from 0 <= i < self.nrows: - b = list(binary(self.basis[i]).zfill(self.ncols)) + b = list(int_to_binary_string(self.basis[i]).zfill(self.ncols)) b.reverse() b.append('\n') s += ''.join(b) s += "\nwords:\n" for ui from 0 <= ui < self.nwords: - b = list(binary(self.words[ui]).zfill(self.ncols)) + b = list(int_to_binary_string(self.words[ui]).zfill(self.ncols)) b.reverse() b.append('\n') s += ''.join(b) From ff3731d4078f7db2caf2b62cb8cc45b777753ef9 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Fri, 17 Apr 2015 14:56:19 +0200 Subject: [PATCH 327/665] Fix the ignored options bug in 3D show() (cf. trac #18238). --- src/sage/plot/plot3d/base.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 83723467203..5f6ba786db0 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -70,7 +70,7 @@ cdef class Graphics3d(SageObject): def __cinit__(self): """ The Cython constructor - + EXAMPLES:: sage: gfx = sage.plot.plot3d.base.Graphics3d() @@ -78,7 +78,7 @@ cdef class Graphics3d(SageObject): {} """ self._extra_kwds = dict() - + def _repr_(self): """ Return a string representation. @@ -133,7 +133,7 @@ cdef class Graphics3d(SageObject): if viewer == 'jmol' and not can_view_jmol: viewer = 'tachyon' ### Second, return the corresponding graphics file if viewer == 'jmol': - return self._rich_repr_jmol(**kwds) + return self._rich_repr_jmol(**opts) elif viewer == 'tachyon': preferred = ( types.OutputImagePng, @@ -142,11 +142,11 @@ cdef class Graphics3d(SageObject): ) for output_container in preferred: if output_container in display_manager.supported_output(): - return self._rich_repr_tachyon(output_container, **kwds) + return self._rich_repr_tachyon(output_container, **opts) elif viewer == 'canvas3d': - return self._rich_repr_canvas3d(**kwds) + return self._rich_repr_canvas3d(**opts) elif viewer == 'wavefront': - return self._rich_repr_wavefront(**kwds) + return self._rich_repr_wavefront(**opts) else: assert False # unreachable @@ -167,7 +167,7 @@ cdef class Graphics3d(SageObject): Instance of :class:`~sage.repl.rich_output.output_graphics.OutputImagePng`, - :class:`~sage.repl.rich_output.output_graphics.OutputImageGif`, or + :class:`~sage.repl.rich_output.output_graphics.OutputImageGif`, or :class:`~sage.repl.rich_output.output_graphics.OutputImageJpg`. EXAMPLES:: @@ -1367,7 +1367,7 @@ end_scene""" % (render_params.antialiasing, def _save_image_png(self, filename, **kwds): r""" Save a PNG rendering. - + This private method is only for use by :meth:`save_image`. EXAMPLES:: From 7eb2326e86c954906d601e75a6909a241fea26b6 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 17 Apr 2015 16:24:02 +0200 Subject: [PATCH 328/665] trac #18213: Review --- src/sage/geometry/polyhedron/library.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 18759e8393d..08339632949 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -67,10 +67,13 @@ from sage.graphs.digraph import DiGraph -def zero_sum_projection(dim): +def zero_sum_projection(d): r""" Return a matrix corresponding to the projection on the orthogonal of - `(1,1,\ldots,1)` in dimension `dim`. + `(1,1,\ldots,1)` in dimension `d`. + + The matrix has dimensions `(d-1)\times d` and is defined over :class:`RDF + `. EXAMPLES:: @@ -83,7 +86,7 @@ def zero_sum_projection(dim): """ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector - basis = [vector(RDF,[1]*i + [-i] + [0]*(dim-i-1)) for i in range(1,dim)] + basis = [vector(RDF,[1]*i + [-i] + [0]*(d-i-1)) for i in range(1,d)] return matrix(RDF, [v / v.norm() for v in basis]) def project_points(*points): @@ -121,7 +124,7 @@ def project_points(*points): ....: assert abs((V[i]-V[j]).norm() - (P[i]-P[j]).norm()) < 0.00001 """ if not points: - return + return [] from sage.modules.free_module_element import vector vecs = [vector(RDF,p) for p in points] m = zero_sum_projection(len(vecs[0])) @@ -292,11 +295,7 @@ def icosahedron(self, exact=True, base_ring=None): Return an icosahedron with edge length 1. The icosahedron is one of the Platonic sold. It has 20 faces and is dual - to the Dodecahedron. - - .. SEEALSO:: - - :meth:`dodecahedron` + to the :meth:`dodecahedron` INPUT: From 562d81a875d02282f9793152ff48057cc9e5e194 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 16:05:35 +0200 Subject: [PATCH 329/665] Trac 18241: better double description (Hrep2Vrep, Vrep2Hrep) --- .../geometry/polyhedron/double_description.py | 149 ++++++++++++------ .../double_description_inhomogeneous.py | 29 ++-- 2 files changed, 122 insertions(+), 56 deletions(-) diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index 289590b9037..88f691dd317 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -32,10 +32,10 @@ ....: (-AA(3).sqrt(),-AA(2).sqrt(),1)]) sage: alg = StandardAlgorithm(A) sage: alg.run().R - ((-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?), + [(-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?), (-0.2411809548974793?, -0.2411809548974793?, 0.2411809548974793?), (0.07665629029830300?, 0.07665629029830300?, 0.2411809548974793?), - (0.5822623322995881?, -0.4177376677004119?, 0.4177376677004119?)) + (0.5822623322995881?, -0.4177376677004119?, 0.4177376677004119?)] REFERENCES: @@ -48,6 +48,7 @@ #***************************************************************************** # Copyright (C) 2014 Volker Braun +# 2015 Vincent Delecroix <20100.delecroix@gmail.com> # # 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 @@ -77,6 +78,8 @@ # construct one by hand. VERIFY_RESULT = True +import itertools + from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix, identity_matrix @@ -150,8 +153,42 @@ def __init__(self, problem, A_rows, R_cols): [-1 -1 1] [ 1/3 1/3 1/3] """ self.problem = problem - self.A = tuple(A_rows) - self.R = tuple(R_cols) + self.A = list(A_rows) + self.R = list(R_cols) + self.one = problem._field.one() + self.zero = problem._field.zero() + + # a cache for scalar product + self.cache = {} + + def _matrix(self, data): + r""" + Create a new matrix using the cached matrix spaces in ``self.problem``. + + INPUT: + + - ``data`` -- a list of lists + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.double_description import \ + ....: DoubleDescriptionPair, Problem + sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) + sage: alg = Problem(A) + sage: DD = DoubleDescriptionPair(alg, + ....: [(1, 0, 1), (0, 1, 1), (-1, -1, 1)], + ....: [(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3), (-1/3, -1/3, 1/3)]) + sage: DD._matrix([[1,2],[3,4]]) + [1 2] + [3 4] + sage: parent(_) + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + """ + if data: + M = self.problem._matrix_space(len(data), len(data[0])) + return M(data) + else: + return self.problem._matrix_space(0,0)() def _make_new(self, A_rows, R_cols): r""" @@ -241,13 +278,7 @@ def inner_product_matrix(self): [0 1 0] [0 0 1] """ - result = [] - for a in self.A: - line = [] - for r in self.R: - line.append(a.inner_product(r)) - result.append(line) - return matrix(self.problem.base_ring(), result) + return self._matrix([[a.inner_product(r) for r in self.R] for a in self.A]) def cone(self): """ @@ -275,7 +306,7 @@ def cone(self): from sage.geometry.polyhedron.constructor import Polyhedron assert self.problem.base_ring() == QQ # required for PPL backend - if len(self.A) == 0: + if not self.A: return Polyhedron(vertices=[[0] * self.problem.dim()], backend='ppl') else: ieqs = [[0] + list(a) for a in self.A] @@ -305,11 +336,10 @@ def verify(self): AssertionError """ from sage.geometry.polyhedron.constructor import Polyhedron - from sage.rings.all import QQ if self.problem.base_ring() is not QQ: return A_cone = self.cone() - R_cone = Polyhedron(vertices=[[0] * self.problem.dim()], rays=self.R, + R_cone = Polyhedron(vertices=[[self.zero] * self.problem.dim()], rays=self.R, base_ring=self.problem.base_ring(), backend='ppl') assert A_cone == R_cone assert A_cone.n_inequalities() <= len(self.A) @@ -343,19 +373,21 @@ def R_by_sign(self, a): neg = [] for r in self.R: sgn = a * r - if sgn > 0: + if sgn == self.zero: + nul.append(r) + elif sgn > self.zero: pos.append(r) - elif sgn < 0: - neg.append(r) else: - nul.append(r) + neg.append(r) return pos, nul, neg - @cached_method def zero_set(self, ray): """ Return the zero set (active set) `Z(r)`. + This method is cached, but the cache is reset to zero in case + :meth:`add_inequality` is called. + INPUT: - ``ray`` -- a ray vector. @@ -372,9 +404,15 @@ def zero_set(self, ray): sage: r = DD.R[0]; r (2/3, -1/3, 1/3) sage: DD.zero_set(r) - ((0, 1, 1), (-1, -1, 1)) + [(0, 1, 1), (-1, -1, 1)] """ - return tuple(a for a in self.A if a.inner_product(ray) == 0) + if ray not in self.cache: + self.cache[ray] = (0, []) + n, t = self.cache[ray] + if n != len(self.A): + t.extend(self.A[i] for i in range(n,len(self.A)) if self.A[i].inner_product(ray) == self.zero) + self.cache[ray] = (len(self.A), t) + return t def is_extremal(self, ray): """ @@ -418,7 +456,7 @@ def are_adjacent(self, r1, r2): Z_r1 = self.zero_set(r1) Z_r2 = self.zero_set(r2) Z_12 = set(Z_r1).intersection(Z_r2) - A_Z12 = matrix(self.problem.base_ring(), list(Z_12)) + A_Z12 = self._matrix(list(Z_12)) return A_Z12.rank() == self.problem.dim() - 2 def dual(self): @@ -475,9 +513,12 @@ def first_coordinate_plane(self): """ R = self.problem.base_ring() d = self.problem.dim() - a_neg = vector(R, [-1] + [0] * (d - 1)) - a_pos = vector(R, [+1] + [0] * (d - 1)) - return self.add_inequality(a_neg).add_inequality(a_pos) + a_neg = vector(R, [-self.one] + [self.zero] * (d - 1)) + a_pos = vector(R, [+self.one] + [self.zero] * (d - 1)) + new = self._make_new(self.A, self.R) + new.add_inequality(a_neg) + new.add_inequality(a_pos) + return new class Problem(SageObject): @@ -509,6 +550,32 @@ def __init__(self, A): self._A = A self._field = A.base_ring().fraction_field() + @cached_method + def _matrix_space(self, nrows, ncols): + r""" + Cache of matrix spaces to avoid their creation in the very demanding + :meth:`StandardDoubleDescriptionPair.add_inequality`. + + EXAMPLES:: + + sage: A = matrix([(1, 1), (-1, 1)]) + sage: from sage.geometry.polyhedron.double_description import Problem + sage: P = Problem(A) + sage: P._matrix_space(2,2) + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: P._matrix_space(3,2) + Full MatrixSpace of 3 by 2 dense matrices over Rational Field + + sage: K. = QuadraticField(2) + sage: A = matrix([[1,sqrt2],[2,0]]) + sage: P = Problem(A) + sage: P._matrix_space(1,2) + Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 + with defining polynomial x^2 - 2 + """ + from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(self.base_ring(), nrows, ncols) + @cached_method def A(self): """ @@ -526,10 +593,9 @@ def A(self): ((1, 1), (-1, 1)) """ rows = [a.change_ring(self._field) for a in self._A.rows()] - map(lambda a: a.set_immutable(), rows) + for a in rows: a.set_immutable() return tuple(rows) - @cached_method def A_matrix(self): """ Return the defining matrix `A`. @@ -546,7 +612,7 @@ def A_matrix(self): [ 1 1] [-1 1] """ - return matrix(self.base_ring(), self.A()) + return self._A def base_ring(self): """ @@ -652,43 +718,38 @@ class StandardDoubleDescriptionPair(DoubleDescriptionPair): def add_inequality(self, a): """ - Return a new double description pair with the inequality `a` added. + Add an inequality to the double description with the inequality ``a`` + added. INPUT: - ``a`` -- vector. An inequality. - OUTPUT: - - A new :class:`StandardDoubleDescriptionPair` instance. - EXAMPLES:: sage: A = matrix([(-1, 1, 0), (-1, 2, 1), (1/2, -1/2, -1)]) sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm sage: DD, _ = StandardAlgorithm(A).initial_pair() - sage: newDD = DD.add_inequality(vector([1,0,0])); newDD + sage: DD.add_inequality(vector([1,0,0])) + sage: DD Double description pair (A, R) defined by [ -1 1 0] [ 1 1 0 0] A = [ -1 2 1], R = [ 1 1 1 1] [ 1/2 -1/2 -1] [ 0 -1 -1/2 -2] [ 1 0 0] """ - from sage.combinat.cartesian_product import CartesianProduct R_pos, R_nul, R_neg = self.R_by_sign(a) - if len(R_neg) == 0: - return self + if not R_neg: + return R_new = [] - for rp, rn in CartesianProduct(R_pos, R_neg): + for rp, rn in itertools.product(R_pos, R_neg): if not self.are_adjacent(rp, rn): continue r = a.inner_product(rp) * rn - a.inner_product(rn) * rp r.set_immutable() R_new.append(r) - R_new = tuple(R_pos + R_nul + R_new) - A_new = self.A + (a,) - return self._make_new(A_new, R_new) - + self.R = R_pos + R_nul + R_new + self.A.append(a) class StandardAlgorithm(Problem): """ @@ -703,7 +764,7 @@ class StandardAlgorithm(Problem): sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm sage: DD = StandardAlgorithm(A).run() sage: DD.R # the extremal rays - ((1/2, 1/2), (-1/2, 1/2)) + [(1/2, 1/2), (-1/2, 1/2)] """ pair_class = StandardDoubleDescriptionPair @@ -731,7 +792,7 @@ def run(self): """ DD, remaining = self.initial_pair() for a in remaining: - DD = DD.add_inequality(a) + DD.add_inequality(a) if VERIFY_RESULT: DD.verify() return DD diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index aa57f3f29fa..c56ea43c738 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -56,7 +56,6 @@ from sage.modules.all import vector from sage.geometry.polyhedron.double_description import StandardAlgorithm as Algorithm - # Compare with PPL if the base ring is QQ. Can be left enabled since # we don't use the Python fallback for polyhedra over QQ unless you # construct one by hand. @@ -252,11 +251,12 @@ def _split_linear_subspace(self): sage: H._split_linear_subspace() (None, [(0, 1, 0), (0, 0, 1)]) """ - lines = self._linear_subspace.matrix().rows() + lines = self._linear_subspace.basis_matrix().rows() L0 = [] L1 = [] + zero = self.base_ring.zero() for l in lines: - if l[0] == 0: + if l[0] == zero: L0.append(l) else: l = l / l[0] @@ -302,13 +302,15 @@ def _extract_Vrep(self, DD): else: # have to really intersect with x_0 = 0 L1 = [] - R1 = [r / r[0] for r in R if r[0] > 0] + zero = self.base_ring.zero() + R1 = [r / r[0] for r in R if r[0] > zero] DD0 = DD.first_coordinate_plane() R0 = map(self._unpivot_ray, DD0.R) vertices = [] + one = self.base_ring.one() for v in R1 + L1: - assert v[0] == 1 + assert v[0] == one vertices.append(v[1:]) self.vertices = vertices if len(vertices) > 0: @@ -332,7 +334,7 @@ def _repr_(self): from sage.matrix.constructor import block_matrix def make_matrix(rows): - return matrix(self.base_ring, len(rows), self.dim, rows).transpose() + return matrix(self.base_ring, len(rows), self.dim, rows).transpose() V = make_matrix(self.vertices) R = make_matrix(self.rays) L = make_matrix(self.lines) @@ -463,11 +465,13 @@ def _init_Vrep(self, vertices, rays, lines): [ 0 -1/2 2/3] [ 0 1/2 -1/3] """ + one = self.base_ring.one() + zero = self.base_ring.zero() homogeneous = \ - [[1] + list(v) for v in vertices] + \ - [[0] + list(r) for r in rays] + \ - [[0] + list(l) for l in lines] + \ - [[0] + [-x for x in l] for l in lines] + [[one] + list(v) for v in vertices] + \ + [[zero] + list(r) for r in rays] + \ + [[zero] + list(l) for l in lines] + \ + [[zero] + [-x for x in l] for l in lines] A = matrix(self.base_ring, homogeneous) return self._pivot_inequalities(A) @@ -488,9 +492,10 @@ def _extract_Hrep(self, DD): sage: DD = StandardAlgorithm(matrix([[1,2], [3,5]])).run() sage: V2H._extract_Hrep(DD) """ + zero = self.base_ring.zero() def is_trivial(ray): # trivial Hrep output 1 >= 0 - return ray[0] > 0 and all(r == 0 for r in ray[1:]) + return ray[0] > zero and all(r == zero for r in ray[1:]) ieqs = map(self._unpivot_ray, DD.R) self.inequalities = [r for r in ieqs if not is_trivial(r)] self.equations = self._linear_subspace.matrix().rows() @@ -544,7 +549,7 @@ def verify(self, vertices, rays, lines): return P = Polyhedron(vertices=vertices, rays=rays, lines=lines, base_ring=QQ, ambient_dim=self.dim) - trivial = [1] + [0] * self.dim # always true equation + trivial = [self.base_ring.one()] + [self.base_ring.zero()] * self.dim # always true equation Q = Polyhedron(ieqs=self.inequalities + [trivial], eqns=self.equations, base_ring=QQ, ambient_dim=self.dim) if not P == Q: From e28fdffe707336b2704eb11010ccf2528e4a60c0 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 16:11:33 +0200 Subject: [PATCH 330/665] Trac 18241: tiny modifs in constructor/parent --- src/sage/geometry/polyhedron/constructor.py | 7 ++----- src/sage/geometry/polyhedron/parent.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index cb5d6ff147a..644d66cda0b 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -446,14 +446,11 @@ def Polyhedron(vertices=None, rays=None, lines=None, parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() - # Convert into base_ring if necessary - def convert_base_ring(lstlst): - return [ [base_ring(x) for x in lst] for lst in lstlst] + + # finally, construct the Polyhedron Hrep = Vrep = None if got_Hrep: Hrep = [ieqs, eqns] if got_Vrep: Vrep = [vertices, rays, lines] - - # finally, construct the Polyhedron return parent(Vrep, Hrep, convert=convert, verbose=verbose) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 9641820f067..d3930bc32a1 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -196,11 +196,13 @@ def an_element(self): sage: Polyhedra(QQ, 4).an_element() A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices """ - p = [0] * self.ambient_dim() + zero = self.base_ring().zero() + one = self.base_ring().one() + p = [zero] * self.ambient_dim() points = [p] for i in range(0,self.ambient_dim()): - p = [0] * self.ambient_dim() - p[i] = 1 + p = [zero] * self.ambient_dim() + p[i] = one points.append(p) return self.element_class(self, [points,[],[]], None) @@ -226,8 +228,9 @@ def some_elements(self): self.element_class(self, None, None), self.element_class(self, None, [[],[]]) ] points = [] + R = self.base_ring() for i in range(0,self.ambient_dim()+5): - points.append([i*j^2 for j in range(0,self.ambient_dim())]) + points.append([R(i*j^2) for j in range(0,self.ambient_dim())]) return [ self.element_class(self, [points[0:self.ambient_dim()+1], [], []], None), self.element_class(self, [points[0:1], points[1:self.ambient_dim()+1], []], None), @@ -279,7 +282,8 @@ def universe(self): sage: P.universe().is_universe() True """ - return self(None, [[[1]+[0]*self.ambient_dim()], []], convert=True) + R = self.base_ring() + return self(None, [[[R.one()]+[R.zero()]*self.ambient_dim()], []], convert=True) @cached_method def Vrepresentation_space(self): From 99c670831a4064246d2cdb2aec32a3e51fd4fd7c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 16:15:16 +0200 Subject: [PATCH 331/665] Trac 18241: trivial case in NumberField.__cmp__ --- src/sage/rings/number_field/number_field.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 10ef93047c7..6ffbab7cb0a 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -2640,6 +2640,8 @@ def __cmp__(self, other): False """ + if self is other: + return 0 if not isinstance(other, NumberField_generic): return cmp(type(self), type(other)) c = cmp(self.base_field(), other.base_field()) From ef13c3612267b85c5b79e77298b4f76368b7d746 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Fri, 17 Apr 2015 16:36:32 +0200 Subject: [PATCH 332/665] 15047: typo --- src/sage/symbolic/ring.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 16255f9264a..9fb42272ca3 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -403,7 +403,7 @@ cdef class SymbolicRing(CommutativeRing): TESTS: - Check that :trac:`15048` is fixed:: + Check that :trac:`15047` is fixed:: sage: latex(SR.wild(0)) \$0 From fac3cffdb326dad1d3c61045d1c33044c99b8b32 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 17:01:52 +0200 Subject: [PATCH 333/665] Trac 18213: (review) more documentation --- src/sage/geometry/polyhedron/library.py | 43 ++++++++++++++++++++----- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 08339632949..a49b3f7ff2d 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -72,7 +72,13 @@ def zero_sum_projection(d): Return a matrix corresponding to the projection on the orthogonal of `(1,1,\ldots,1)` in dimension `d`. - The matrix has dimensions `(d-1)\times d` and is defined over :class:`RDF + The projection maps the orthonormal basis `(1,-1,0,\ldots,0) / \sqrt(2)`, + `(1,1,-1,0,\ldots,0) / \sqrt(3)`, \ldots, `(1,1,\ldots,1,-1) / \sqrt(d)` to + the canonical basis in `\RR^{d-1}`. + + OUTPUT: + + A matrix of dimensions `(d-1)\times d` defined over :class:`RDF `. EXAMPLES:: @@ -97,6 +103,8 @@ def project_points(*points): made of zero sum vector. Hence, if the set of points have all equal sums, then their projection is isometric (as a set of points). + The projection used is the matrix given by :func:`zero_sum_projection`. + EXAMPLES:: sage: from sage.geometry.polyhedron.library import project_points @@ -105,8 +113,9 @@ def project_points(*points): sage: project_points([1,2,3],[3,3,5]) [(-0.7071067811865475, -1.2247448713915892), (0.0, -1.6329931618554523)] - This projection is the only one compatible with the restriction to the first - coordinates:: + These projections are compatible with the restriction. More precisely, given + a vector `v`, the projection of `v` restricted to the first `i` coordinates + will be equal to the projection of the first `i+1` coordinates of `v`:: sage: project_points([1,2]) [(-0.7071067811865475)] @@ -114,6 +123,8 @@ def project_points(*points): [(-0.7071067811865475, -1.2247448713915892)] sage: project_points([1,2,3,4]) [(-0.7071067811865475, -1.2247448713915892, -1.7320508075688776)] + sage: project_points([1,2,3,4,0]) + [(-0.7071067811865475, -1.2247448713915892, -1.7320508075688776, 2.23606797749979)] Check that it is (almost) an isometry:: @@ -273,14 +284,14 @@ def simplex(self, dim=3, project=False): Its volume is `\sqrt{d+1} / d!`:: sage: s5 = polytopes.simplex(5, project=True) - sage: s5.volume() - 0.020412414522984975 + sage: s5.volume() # abs tol 1e-10 + 0.0204124145231931 sage: sqrt(6.) / factorial(5) 0.0204124145231931 sage: s6 = polytopes.simplex(6, project=True) - sage: s6.volume() - 0.003674654598885692 + sage: s6.volume() # abs tol 1e-10 + 0.00367465459870082 sage: sqrt(7.) / factorial(6) 0.00367465459870082 """ @@ -295,7 +306,7 @@ def icosahedron(self, exact=True, base_ring=None): Return an icosahedron with edge length 1. The icosahedron is one of the Platonic sold. It has 20 faces and is dual - to the :meth:`dodecahedron` + to the :meth:`dodecahedron`. INPUT: @@ -322,6 +333,22 @@ def icosahedron(self, exact=True, base_ring=None): Real Double Field sage: ico.volume() 2.1816949907715726 + + A version using `AA `:: + + sage: ico = polytopes.icosahedron(base_ring=AA) # long time + sage: ico.base_ring() # long time + Algebraic Real Field + sage: ico.volume() # long time + 2.181694990624913? + + Note that if base ring is provided it must contain the square root of + `5`. Otherwise you will get an error:: + + sage: polytopes.icosahedron(base_ring=QQ) + Traceback (most recent call last): + ... + TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField From d358636766bf0abae69bb07f154053180bd14a8a Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 17 Apr 2015 18:31:22 +0100 Subject: [PATCH 334/665] a workaround for gcc 4.9, to enable c++ building, cf. #18240 --- build/pkgs/mpir/patches/gmp-h_in.patch | 23 +++++++++++++++++++++++ build/pkgs/mpir/patches/mpirxx_h.patch | 12 ++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 build/pkgs/mpir/patches/gmp-h_in.patch create mode 100644 build/pkgs/mpir/patches/mpirxx_h.patch diff --git a/build/pkgs/mpir/patches/gmp-h_in.patch b/build/pkgs/mpir/patches/gmp-h_in.patch new file mode 100644 index 00000000000..69854f19ee5 --- /dev/null +++ b/build/pkgs/mpir/patches/gmp-h_in.patch @@ -0,0 +1,23 @@ +# porting to gcc 4.9; see #18240 +--- src/gmp-h.in ++++ src/gmp-h.in +@@ -29,6 +29,8 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + #endif + + #if defined (__cplusplus) ++ ++#include /* for size_t */ + #include /* for std::istream, std::ostream, std::string */ + #include + #endif +@@ -50,9 +52,7 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + #define __GNU_MP__ 4 + + #define __need_size_t /* tell gcc stddef.h we only want size_t */ +-#if defined (__cplusplus) +-#include /* for size_t */ +-#else ++#if ! defined (__cplusplus) + #include /* for size_t */ + #endif + #undef __need_size_t diff --git a/build/pkgs/mpir/patches/mpirxx_h.patch b/build/pkgs/mpir/patches/mpirxx_h.patch new file mode 100644 index 00000000000..62682433fc4 --- /dev/null +++ b/build/pkgs/mpir/patches/mpirxx_h.patch @@ -0,0 +1,12 @@ +# porting to gcc 4.9; see #18240 +--- src/mpirxx.h ++++ src/mpirxx.h +@@ -32,6 +32,8 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + #ifndef __GMP_PLUSPLUS__ + #define __GMP_PLUSPLUS__ + ++#include /* for size_t */ ++ + #include + + #include /* for strlen */ From 6b9a4c4a1324f722c3f422636a07e9ccee4d6bf8 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 17 Apr 2015 10:38:35 -0700 Subject: [PATCH 335/665] seems working dommax to substitute for dominant maximal --- .../root_system/integrable_representations.py | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index ad539c78ed0..b03df437213 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -21,6 +21,7 @@ from sage.misc.all import cached_method from sage.matrix.constructor import Matrix from sage.functions.other import floor +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet # TODO: Make this a proper parent and implement actions class IntegrableRepresentation(CategoryObject, UniqueRepresentation): @@ -251,7 +252,7 @@ def level(self): The level of the representation equals `(\\rho|\delta)`. See [Kac] section 12.4. """ - return self._inner_pq(self._Lam, self._delta) + return ZZ(self._inner_pq(self._Lam, self._delta)) def coxeter_number(self): """ @@ -411,7 +412,7 @@ def to_weight(self, n): return self._Lam - self._P.sum(val * alpha[I[i]] for i,val in enumerate(n)) - def _from_weight_helper(self, mu): + def _from_weight_helper(self, mu, check=False): r""" Return ``(n[0], n[1], ...)`` such that ``mu = sum n[i]*alpha[i]``. @@ -432,9 +433,12 @@ def _from_weight_helper(self, mu): zero = ZZ.zero() for i in self._index_set_classical: # -1 for indexing - ret.append( ZZ(sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) - for j in self._index_set_classical)) ) - return tuple(ret) + ret.append( sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) + for j in self._index_set_classical) ) + if check: + return all(x in ZZ for x in ret) + else: + return tuple(ZZ(x) for x in ret) def from_weight(self, mu): """ @@ -621,6 +625,31 @@ def m(self, n): print "m: error - failed to compute m%s"%n.__repr__() return ret + def dommax(self): + """ + A weight `\\mu` is *maximal* if it has nonzero multiplicity but + `\\mu+\\delta`` has multiplicity zero. There are a finite number + of dominant maximal weights. + + This function will replace dominant maximal after it has been + fully tested. + + """ + k = self.level() + Lambda = self._P.fundamental_weights() + def next_level(wt): + return [wt + Lambda[i] for i in self._index_set_classical if (wt + Lambda[i]).level() <= k] + R = RecursivelyEnumeratedSet([self._P.zero()], next_level) + candidates = [x + (k - x.level())*Lambda[0] for x in list(R)] + ret = [] + for x in candidates: + if self._from_weight_helper(x, check=True): + t = 0 + while self.m(self.from_weight(x-t*self._delta)) == 0: + t += 1 + ret.append(x-t*self._delta) + return ret + # FIXME: Make this generate itself without having needing to be called by string() #@lazy_attribute def dominant_maximal(self): From c5eef589461ef5650c84fa237f2445573a52a4a4 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 17 Apr 2015 13:50:21 -0400 Subject: [PATCH 336/665] fix some more option handlin in 3d plots --- src/sage/plot/plot3d/base.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 5f6ba786db0..7639f441d54 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -238,13 +238,13 @@ cdef class Graphics3d(SageObject): opts['aspect_ratio'], zoom, ) - T.export_jmol(scene_zip, zoom=zoom*100, **kwds) + T.export_jmol(scene_zip, zoom=zoom*100, **opts) from sage.interfaces.jmoldata import JmolData jdata = JmolData() if not jdata.is_jvm_available(): # We can only use JMol to generate preview if a jvm is installed from sage.repl.rich_output.output_graphics import OutputImagePng - tachyon = self._rich_repr_tachyon(OutputImagePng, **kwds) + tachyon = self._rich_repr_tachyon(OutputImagePng, **opts) tachyon.png.save_as(preview_png) else: # Java needs absolute paths @@ -1388,10 +1388,10 @@ end_scene""" % (render_params.antialiasing, viewer = opts['viewer'] if viewer == 'tachyon': from sage.repl.rich_output.output_catalog import OutputImagePng - render = self._rich_repr_tachyon(OutputImagePng, **kwds) + render = self._rich_repr_tachyon(OutputImagePng, **opts) render.png.save_as(filename) elif viewer == 'jmol': - scene = self._rich_repr_jmol(**kwds) + scene = self._rich_repr_jmol(**opts) scene.preview_png.save_as(filename) else: raise ValueError('cannot use viewer={0} to render image'.format(viewer)) From ef3bb5d985ee65e46d89277a3833af40953bc59c Mon Sep 17 00:00:00 2001 From: Simon King Date: Fri, 17 Apr 2015 19:54:48 +0200 Subject: [PATCH 337/665] Add a warning not to use coerce actions outside of the coercion model --- src/sage/structure/coerce_actions.pyx | 103 ++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 0adb72e1969..c11928b3c29 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -63,7 +63,12 @@ cdef class GenericAction(Action): def __init__(self, Parent G, S, is_left, bint check=True): """ - TESTS:: + TESTS: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: M = MatrixSpace(ZZ,2) sage: sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) @@ -94,7 +99,13 @@ cdef class GenericAction(Action): result elements live. Typically, this should be the same as the acted upon set. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, for + otherwise they could be garbage collected, giving rise to random + errors. :: + sage: M = MatrixSpace(ZZ,2) sage: A = sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) @@ -106,6 +117,7 @@ cdef class GenericAction(Action): sage: A = sage.structure.coerce_actions.ActOnAction(S3, QQxyz, False) sage: A.codomain() Multivariate Polynomial Ring in x, y, z over Rational Field + """ if self._codomain is None: self._codomain = parent_c(self.act(an_element(self.G), @@ -164,7 +176,12 @@ def detect_element_action(Parent X, Y, bint X_on_left, X_el=None, Y_el=None): r""" Returns an action of X on Y or Y on X as defined by elements X, if any. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import detect_element_action sage: ZZx = ZZ['x'] @@ -272,7 +289,12 @@ cdef class ModuleAction(Action): base ring. The simplest example to keep in mind is R acting on the polynomial ring R[x]. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import LeftModuleAction sage: ZZx = ZZ['x'] @@ -361,7 +383,12 @@ cdef class ModuleAction(Action): """ The default name of this action type, which is has a sane default. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the + coercion model. For this test, we need to strongly reference the + domains, for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import LeftModuleAction, RightModuleAction sage: ZZx = ZZ['x'] @@ -374,6 +401,7 @@ cdef class ModuleAction(Action): sage: GF5t = GF5[['t']] sage: RightModuleAction(GF5, GF5t) Right scalar multiplication by Finite Field of size 5 on Power Series Ring in t over Finite Field of size 5 + """ return "scalar multiplication" @@ -381,10 +409,16 @@ cdef class ModuleAction(Action): """ The codomain of self, which may or may not be equal to the domain. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import LeftModuleAction - sage: A = LeftModuleAction(QQ, ZZ['x,y,z']) + sage: ZZxyz = ZZ['x,y,z'] + sage: A = LeftModuleAction(QQ, ZZxyz) sage: A.codomain() Multivariate Polynomial Ring in x, y, z over Rational Field """ @@ -396,10 +430,16 @@ cdef class ModuleAction(Action): """ The domain of self, which is the module that is being acted on. - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import LeftModuleAction - sage: A = LeftModuleAction(QQ, ZZ['x,y,z']) + sage: ZZxyz = ZZ['x,y,z'] + sage: A = LeftModuleAction(QQ, ZZxyz) sage: A.domain() Multivariate Polynomial Ring in x, y, z over Integer Ring """ @@ -407,7 +447,12 @@ cdef class ModuleAction(Action): def __invert__(self): """ - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, for + otherwise they could be garbage collected, giving rise to random + errors. :: sage: from sage.structure.coerce_actions import RightModuleAction @@ -499,7 +544,12 @@ cdef class LeftModuleAction(ModuleAction): first argument (the left side) and the module element as the second argument (the right side). - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import LeftModuleAction sage: R. = QQ['x'] @@ -531,7 +581,12 @@ cdef class RightModuleAction(ModuleAction): first argument (the left side) and the ring element as the second argument (the right side). - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the domains, + for otherwise they could be garbage collected, giving rise to + random errors. :: sage: from sage.structure.coerce_actions import RightModuleAction sage: R. = QQ['x'] @@ -573,6 +628,12 @@ cdef class IntegerMulAction(Action): Both addition and negation must be defined on the set `M`. + NOTE: + + This class is used internally in Sage's coercion model. Outside of the + coercion model, special precautions are needed to prevent domains of + the action from being garbage collected. + INPUT: - An integer ring, ``ZZ`` @@ -601,7 +662,12 @@ cdef class IntegerMulAction(Action): cpdef _call_(self, nn, a): """ - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the field + ``GF(101)``, for otherwise it could be garbage collected, giving rise + to random errors. :: sage: from sage.structure.coerce_actions import IntegerMulAction sage: GF101 = GF(101) @@ -624,8 +690,7 @@ cdef class IntegerMulAction(Action): This used to hang before :trac:`17844`:: - sage: GF5 = GF(5) - sage: E = EllipticCurve(GF5, [4,0]) + sage: E = EllipticCurve(GF(5), [4,0]) sage: P = E.random_element() sage: (-2^63)*P (0 : 1 : 0) @@ -636,6 +701,7 @@ cdef class IntegerMulAction(Action): Traceback (most recent call last): ... AlarmInterrupt + """ if not self._is_left: a, nn = nn, a @@ -660,7 +726,12 @@ cdef class IntegerMulAction(Action): def _repr_name_(self): """ - EXAMPLES:: + EXAMPLES: + + Note that coerce actions should only be used inside of the coercion + model. For this test, we need to strongly reference the field + ``GF(5)``, for otherwise it could be garbage collected, giving rise + to random errors. :: sage: from sage.structure.coerce_actions import IntegerMulAction sage: GF5 = GF(5) From b156ca504d368899f3a50dd0ffffebac0839b491 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 17 Apr 2015 14:21:09 -0400 Subject: [PATCH 338/665] Use zoom instead of zoom*100 --- src/sage/plot/plot3d/base.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index 7639f441d54..fd670b5ad38 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -238,7 +238,7 @@ cdef class Graphics3d(SageObject): opts['aspect_ratio'], zoom, ) - T.export_jmol(scene_zip, zoom=zoom*100, **opts) + T.export_jmol(scene_zip, **opts) from sage.interfaces.jmoldata import JmolData jdata = JmolData() if not jdata.is_jvm_available(): @@ -821,7 +821,7 @@ end_scene""" % (render_params.antialiasing, return "\n".join(flatten_list([self.obj_repr(self.default_render_params()), ""])) def export_jmol(self, filename='jmol_shape.jmol', force_reload=False, - zoom=100, spin=False, background=(1,1,1), stereo=False, + zoom=1, spin=False, background=(1,1,1), stereo=False, mesh=False, dots=False, perspective_depth = True, orientation = (-764,-346,-545,76.39), **ignored_kwds): @@ -916,7 +916,7 @@ end_scene""" % (render_params.antialiasing, f.write('moveto 0 %s %s %s %s\n'%tuple(orientation)) f.write('centerAt absolute {0 0 0}\n') - f.write('zoom %s\n'%zoom) + f.write('zoom {0}\n'.format(zoom * 100)) f.write('frank OFF\n') # jmol logo if perspective_depth: From e2557233dc370db99b0625286f1d7b883146d5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 17 Apr 2015 21:05:39 +0200 Subject: [PATCH 339/665] trac #18161 some details --- src/sage/ext/interactive_constructors_c.pyx | 16 ++++++++-------- src/sage/repl/ipython_tests.py | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/ext/interactive_constructors_c.pyx b/src/sage/ext/interactive_constructors_c.pyx index d6051edcb25..c14d66529af 100644 --- a/src/sage/ext/interactive_constructors_c.pyx +++ b/src/sage/ext/interactive_constructors_c.pyx @@ -20,7 +20,7 @@ def inject_on(verbose=True): INPUT: - - verbose (default: True) if True, print which constructors become + - verbose (default: ``True``) if ``True``, print which constructors become interactive, and also print variables as they are implicitly defined. EXAMPLES:: @@ -107,7 +107,7 @@ def FiniteField(*args, **kwds): """ Construct a finite field and inject the variables of the finite field to the global interactive interpreter. Use - inject=False to not inject the variables. This is a wrapper + ``inject=False`` to not inject the variables. This is a wrapper around the following function: FiniteField """ t = _do_inject(kwds) @@ -120,7 +120,7 @@ def FractionField(*args, **kwds): """ Construct the fraction field of a field and inject the generators of the fraction field to the global interactive interpreter. Use - inject=False to not inject the variables. This is a wrapper + ``inject=False`` to not inject the variables. This is a wrapper around the following function: FractionField EXAMPLES (that illustrate interactive injection of variables):: @@ -141,7 +141,7 @@ Frac = FractionField def FreeMonoid(*args, **kwds): """ Construct a free monoid and inject the variables of the monoid - into the global interactive interpreter. Use inject=False to not + into the global interactive interpreter. Use ``inject=False`` to not inject the variables. This is a wrapper around the following function: FreeMonoid @@ -170,7 +170,7 @@ def LaurentSeriesRing(*args, **kwds): """ Construct the Laurent series ring over a ring, and inject the generator into the interpreter's global namespace. Use - inject=False to not inject the variables. This is a wrapper + ``inject=False`` to not inject the variables. This is a wrapper around the following function: LaurentSeries @@ -183,7 +183,7 @@ def NumberField(*args, **kwds): """ Construct a number field, and inject the generator of the number fraction field into the interpreters global namespace. Use - inject=False to not inject the variables. This is a wrapper + ``inject=False`` to not inject the variables. This is a wrapper around the following function: NumberField """ @@ -194,7 +194,7 @@ def NumberField(*args, **kwds): def quotient(R, I, names, inject=True): """ Construct the quotient R/I and name the generators, which are - then injected into the module scope (if inject=True). + then injected into the module scope (if ``inject=True``). EXAMPLES:: @@ -222,7 +222,7 @@ def PolynomialRing(*args, **kwds): """ Construct a polynomial ring and inject the variables of the polynomial ring to the global interactive interpreter. Use - inject=False to not inject the variables. This is a wrapper + ``inject=False`` to not inject the variables. This is a wrapper around the following function: PolynomialRing MORE EXAMPLES: diff --git a/src/sage/repl/ipython_tests.py b/src/sage/repl/ipython_tests.py index f940755f496..0fa568dfc2a 100644 --- a/src/sage/repl/ipython_tests.py +++ b/src/sage/repl/ipython_tests.py @@ -64,7 +64,7 @@ def dummy(argument, optional=None): - ``optional`` -- anything (optional). Dummy optional. - EXAMPLES: + EXAMPLES:: ... """ @@ -102,6 +102,7 @@ def __cinit__(self): Type: type ''' + def dummy(argument, optional=None): """ Dummy Docstring Title @@ -114,7 +115,7 @@ def dummy(argument, optional=None): - ``optional`` -- anything (optional). Dummy optional. - EXAMPLES: + EXAMPLES:: sage: from sage.repl.ipython_tests import dummy sage: dummy(1) From 7dbf867236b6c9c88acd25009fdf8453571b9d75 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 22:15:49 +0200 Subject: [PATCH 340/665] Trac 18239: fix PermutationGroup_generic.__iter__ --- src/sage/groups/perm_gps/permgroup.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 14c34d7e17a..509fcf39c22 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -703,7 +703,6 @@ def _coerce_impl(self, x): return self._element_class()(x.cycle_tuples(), self, check=False) raise TypeError("no implicit coercion of element into permutation group") - @cached_method def list(self): """ Return list of all elements of this group. @@ -782,9 +781,21 @@ def __iter__(self): sage: G = PermutationGroup([[(1,2,3)], [(1,2)]]) sage: [a for a in G] [(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)] + + Test that it is possible to iterate through moderately large groups + (trac:`18239`):: + + sage: p = [(i,i+1) for i in range(1,601,2)] + sage: q = [tuple(range(1+i,601,3)) for i in range(3)] + sage: A = PermutationGroup([p,q]) + sage: A.cardinality() + 60000 + sage: for x in A: + ....: pass """ - for g in self._gap_().Elements(): - yield self._element_class()(g, self, check=False) + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + return iter(RecursivelyEnumeratedSet(seeds=[self.one()], + successors=lambda g: (g._mul_(h) for h in self.gens()))) def gens(self): """ From 1e75b5bd931cf025ef7fa64617021a02474508c8 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 22:32:36 +0200 Subject: [PATCH 341/665] Trac 18239: fix doctests --- src/sage/groups/perm_gps/permgroup.py | 14 +++++++++----- src/sage/groups/perm_gps/permgroup_named.py | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 509fcf39c22..9a25f05a7ed 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -711,7 +711,11 @@ def list(self): sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.list() - [(), (3,4), (2,3), (2,3,4), (2,4,3), (2,4), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4), (1,2,4,3), (1,2,4), (1,3,2), (1,3,4,2), (1,3), (1,3,4), (1,3)(2,4), (1,3,2,4), (1,4,3,2), (1,4,2), (1,4,3), (1,4), (1,4,2,3), (1,4)(2,3)] + [(), (1,2), (1,2,3,4), (1,3,4), (2,3,4), (1,3)(2,4), + (1,4,3,2), (1,3,2,4), (1,2,4,3), (1,3,4,2), + (1,4,2,3), (2,4,3), (1,4,3), (1,3,2), (1,4)(2,3), + (1,4,2), (3,4), (2,4), (1,4), (2,3), (1,3), (1,2,3), + (1,2,4), (1,2)(3,4)] sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b')); G Permutation Group with generators [('a','b')] @@ -780,7 +784,7 @@ def __iter__(self): sage: G = PermutationGroup([[(1,2,3)], [(1,2)]]) sage: [a for a in G] - [(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)] + [(), (1,2), (1,2,3), (2,3), (1,3,2), (1,3)] Test that it is possible to iterate through moderately large groups (trac:`18239`):: @@ -790,8 +794,8 @@ def __iter__(self): sage: A = PermutationGroup([p,q]) sage: A.cardinality() 60000 - sage: for x in A: - ....: pass + sage: for x in A: # long time - 2 secs + ....: pass # long time """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet return iter(RecursivelyEnumeratedSet(seeds=[self.one()], @@ -3084,7 +3088,7 @@ def cosets(self, S, side='right'): is possible. :: sage: A = AlternatingGroup(4) - sage: face_turn = A.list()[4]; face_turn + sage: face_turn = A('(1,2,3)'); face_turn (1,2,3) sage: stabilizer = A.subgroup([face_turn]) sage: rc = A.cosets(stabilizer, side='right'); rc diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 7c10a36baa3..05025a5e44f 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1250,15 +1250,18 @@ def _repr_(self): class DihedralGroup(PermutationGroup_unique): def __init__(self, n): """ - The Dihedral group of order $2n$ for any integer $n\geq 1$. + The Dihedral group of order `2n` for any integer `n\geq 1`. INPUT: - n -- a positive integer + + - ``n`` -- a positive integer OUTPUT: - -- the dihedral group of order 2*n, as a permutation group - .. note:: + The dihedral group of order `2n`, as a permutation group + + .. NOTE:: + This group is also available via ``groups.permutation.Dihedral()``. EXAMPLES:: @@ -1274,7 +1277,8 @@ def __init__(self, n): sage: DihedralGroup(5).gens() [(1,2,3,4,5), (1,5)(2,4)] sage: list(DihedralGroup(5)) - [(), (2,5)(3,4), (1,2)(3,5), (1,2,3,4,5), (1,3)(4,5), (1,3,5,2,4), (1,4)(2,3), (1,4,2,5,3), (1,5,4,3,2), (1,5)(2,4)] + [(), (1,5)(2,4), (1,2,3,4,5), (2,5)(3,4), (1,4)(2,3), (1,3,5,2,4), + (1,5,4,3,2), (1,4,2,5,3), (1,2)(3,5), (1,3)(4,5)] sage: G = DihedralGroup(6) sage: G.order() From d6494fd229e40573b2a86ba64c8cde241ab795b3 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 17 Apr 2015 22:37:15 +0200 Subject: [PATCH 342/665] trac #18239: Small simplification and removal of unused cayley_graph functions --- src/sage/categories/semigroups.py | 9 ++-- src/sage/groups/group.pyx | 60 --------------------------- src/sage/groups/old.pyx | 60 --------------------------- src/sage/groups/perm_gps/permgroup.py | 2 +- 4 files changed, 7 insertions(+), 124 deletions(-) diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index bcdcda64eba..17a5e17bd4b 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -305,8 +305,9 @@ def cayley_graph(self, side="right", simple=False, elements = None, generators = raise ValueError("option 'side' must be 'left', 'right' or 'twosided'") if elements is None: assert self.is_finite(), "elements should be specified for infinite semigroups" - elements = list(self) - elements_set = set(elements) + elements = self + else: + elements = set(elements) if simple or self in Groups(): result = DiGraph() else: @@ -329,7 +330,9 @@ def add_edge(source, target, label, side_label): Skips edges whose targets are not in elements Return an appropriate edge given the options """ - if target not in elements_set: return + if (elements is not self and + target not in elements): + return if simple: result.add_edge([source, target]) elif side == "twosided": diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index 0939dcaa6e8..a9fd3e41214 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -316,63 +316,3 @@ cdef class FiniteGroup(Group): True """ return True - - def cayley_graph(self, connecting_set=None): - """ - Return the Cayley graph for this finite group. - - INPUT: - - - ``connecting_set`` -- (optional) list of elements to use for - edges, default is the stored generators - - OUTPUT: - - The Cayley graph as a Sage DiGraph object. To plot the graph - with with different colors - - EXAMPLES:: - - sage: D4 = DihedralGroup(4); D4 - Dihedral group of order 8 as a permutation group - sage: G = D4.cayley_graph() - sage: show(G, color_by_label=True, edge_labels=True) - sage: A5 = AlternatingGroup(5); A5 - Alternating group of order 5!/2 as a permutation group - sage: G = A5.cayley_graph() - sage: G.show3d(color_by_label=True, edge_size=0.01, edge_size2=0.02, vertex_size=0.03) - sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1):G.vertices()}, bgcolor=(0,0,0), color_by_label=True, xres=700, yres=700, iterations=200) # long time (less than a minute) - sage: G.num_edges() - 120 - sage: G = A5.cayley_graph(connecting_set=[A5.gens()[0]]) - sage: G.num_edges() - 60 - sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i]) - sage: g.cayley_graph(connecting_set=[(1,2),(2,3)]) - Digraph on 120 vertices - - sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices() - [()] - - AUTHORS: - - - Bobby Moretti (2007-08-10) - - Robert Miller (2008-05-01): editing - """ - if connecting_set is None: - connecting_set = self.gens() - else: - if any(g not in self for g in connecting_set): - raise ValueError("Each element of the connecting set must be in the group!") - connecting_set = [self(g) for g in connecting_set] - from sage.graphs.all import DiGraph - arrows = {} - for x in self: - arrows[x] = {} - for g in connecting_set: - xg = x*g # cache the multiplication - if not xg == x: - arrows[x][xg] = g - - return DiGraph(arrows, implementation='networkx') - diff --git a/src/sage/groups/old.pyx b/src/sage/groups/old.pyx index 3abcd7976f9..50f834a8a3d 100644 --- a/src/sage/groups/old.pyx +++ b/src/sage/groups/old.pyx @@ -239,66 +239,6 @@ cdef class FiniteGroup(Group): """ return True - def cayley_graph(self, connecting_set=None): - """ - Returns the cayley graph for this finite group, as a Sage DiGraph - object. To plot the graph with with different colors - - INPUT:: - - `connecting_set` - (optional) list of elements to use for edges, - default is the stored generators - - EXAMPLES:: - - sage: D4 = DihedralGroup(4); D4 - Dihedral group of order 8 as a permutation group - sage: G = D4.cayley_graph() - sage: show(G, color_by_label=True, edge_labels=True) - sage: A5 = AlternatingGroup(5); A5 - Alternating group of order 5!/2 as a permutation group - sage: G = A5.cayley_graph() - sage: G.show3d(color_by_label=True, edge_size=0.01, edge_size2=0.02, vertex_size=0.03) - sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1):G.vertices()}, bgcolor=(0,0,0), color_by_label=True, xres=700, yres=700, iterations=200) # long time (less than a minute) - sage: G.num_edges() - 120 - sage: G = A5.cayley_graph(connecting_set=[A5.gens()[0]]) - sage: G.num_edges() - 60 - sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i]) - sage: g.cayley_graph(connecting_set=[(1,2),(2,3)]) - Digraph on 120 vertices - - :: - - sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices() - [()] - - AUTHORS: - - - Bobby Moretti (2007-08-10) - - - Robert Miller (2008-05-01): editing - """ - if connecting_set is None: - connecting_set = self.gens() - else: - try: - for g in connecting_set: - assert g in self - except AssertionError: - raise RuntimeError("Each element of the connecting set must be in the group!") - connecting_set = [self(g) for g in connecting_set] - from sage.graphs.all import DiGraph - arrows = {} - for x in self: - arrows[x] = {} - for g in connecting_set: - xg = x*g # cache the multiplication - if not xg == x: - arrows[x][xg] = g - - return DiGraph(arrows, implementation='networkx') cdef class AlgebraicGroup(Group): """ diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 9a25f05a7ed..d60fb1ccd3d 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -338,7 +338,7 @@ def PermutationGroup(gens=None, gap_group=None, domain=None, canonicalize=True, canonicalize=canonicalize, category=category) -class PermutationGroup_generic(group.Group): +class PermutationGroup_generic(group.FiniteGroup): """ EXAMPLES:: From 21e70a7a66aa10fd41afb36e772352c52634fc76 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Fri, 17 Apr 2015 23:52:29 +0200 Subject: [PATCH 343/665] Trac 18213: review commit --- src/sage/geometry/polyhedron/library.py | 63 +++++++++++++------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index a49b3f7ff2d..f6dcfed1fc3 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -267,7 +267,8 @@ def simplex(self, dim=3, project=False): - ``project`` -- (boolean, default ``False``) if ``True``, the polytope is (isometrically) projected to a vector space of dimension ``dim-1``. This operation turns the coordinates into floating point - approximations. + approximations and corresponds to the projection given by the matrix + from :func:`zero_sum_projection`. EXAMPLES:: @@ -313,10 +314,11 @@ def icosahedron(self, exact=True, base_ring=None): - ``exact`` -- (boolean, default ``True``) If ``False`` use an approximate ring for the coordinates. - - ``base_ring`` -- the ring in which the coordinates will belong to. If - it is not provided and ``exact=True`` it will be a the number field - `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it - will be the real double field. + - ``base_ring`` -- (optional) the ring in which the coordinates will + belong to. Note that this ring must contain `\sqrt(5)`. If it is not + provided and ``exact=True`` it will be the number field + `\QQ[\sqrt(5)]` and if ``exact=False`` it will be the real double + field. EXAMPLES:: @@ -372,19 +374,18 @@ def dodecahedron(self, exact=True, base_ring=None): """ Return a dodecahedron. - .. SEEALSO:: - - :meth:`icosahedron` + The dodecahedron is the Platonic solid dual to the :meth:`icosahedron`. INPUT: - ``exact`` -- (boolean, default ``True``) If ``False`` use an approximate ring for the coordinates. - - ``base_ring`` -- the ring in which the coordinates will belong to. If - it is not provided and ``exact=True`` it will be a the number field - `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it - will be the real double field. + - ``base_ring`` -- (optional) the ring in which the coordinates will + belong to. Note that this ring must contain `\sqrt(5)`. If it is not + provided and ``exact=True`` it will be the number field + `\QQ[\sqrt(5)]` and if ``exact=False`` it will be the real double + field. EXAMPLES:: @@ -399,8 +400,15 @@ def dodecahedron(self, exact=True, base_ring=None): sage: d12 = polytopes.dodecahedron(exact=False) sage: d12.base_ring() Real Double Field + + Here is an error with a field that does not contain `\sqrt(5)`:: + + sage: polytopes.dodecahedron(base_ring=QQ) + Traceback (most recent call last): + ... + TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational """ - return self.icosahedron(exact=exact).polar() + return self.icosahedron(exact=exact, base_ring=base_ring).polar() def small_rhombicuboctahedron(self, exact=True, base_ring=None): """ @@ -757,7 +765,7 @@ def six_hundred_cell(self, exact=False): .. WARNING:: - The coordinates are not exact. The computation with exact + The coordinates are not exact by default. The computation with exact coordinates takes a huge amount of time. INPUT: @@ -779,12 +787,6 @@ def six_hundred_cell(self, exact=False): sage: len(list(p600.bounded_edges())) # not tested - very long time 120 """ - q12 = QQ((1,2)) - verts = [[s1*q12, s2*q12, s3*q12, s4*q12] for s1,s2,s3,s4 in itertools.product([1,-1], repeat=4)] - V = ZZ**4 - verts.extend(V.basis()) - verts.extend(-v for v in V.basis()) - if exact: from sage.rings.number_field.number_field import QuadraticField K = QuadraticField(5, 'sqrt5') @@ -795,7 +797,13 @@ def six_hundred_cell(self, exact=False): g = (1 + RDF(5).sqrt()) / 2 base_ring = RDF - pts = [[s1 * q12, s2*g/2, s3/(2*g), 0] for (s1,s2,s3) in itertools.product([1,-1], repeat=3)] + q12 = base_ring(1) / base_ring(2) + z = base_ring.zero() + verts = [[s1*q12, s2*q12, s3*q12, s4*q12] for s1,s2,s3,s4 in itertools.product([1,-1], repeat=4)] + V = (base_ring)**4 + verts.extend(V.basis()) + verts.extend(-v for v in V.basis()) + pts = [[s1 * q12, s2*g/2, s3/(2*g), z] for (s1,s2,s3) in itertools.product([1,-1], repeat=3)] for p in AlternatingGroup(4): verts.extend(p(x) for x in pts) return Polyhedron(vertices=verts, base_ring=base_ring) @@ -817,8 +825,6 @@ def cyclic_polytope(self, dim, n, base_ring=QQ): - ``base_ring`` -- either ``QQ`` (default) or ``RDF``. - OUTPUT: - EXAMPLES:: sage: c = polytopes.cyclic_polytope(4,10) @@ -851,7 +857,8 @@ def hypersimplex(self, dim, k, project=False): - ``project`` -- (boolean, default ``False``) if ``True``, the polytope is (isometrically) projected to a vector space of dimension ``dim-1``. This operation turns the coordinates into floating point - approximations. + approximations and corresponds to the projection given by the matrix + from :func:`zero_sum_projection`. EXAMPLES:: @@ -887,15 +894,11 @@ def permutahedron(self, n, project=False): - ``project`` -- (boolean, default ``False``) if ``True``, the polytope is (isometrically) projected to a vector space of dimension ``dim-1``. This operation turns the coordinates into floating point - approximations. - - OUTPUT: - - A Polyhedron object representing the permutahedron. + approximations and corresponds to the projection given by the matrix + from :func:`zero_sum_projection`. EXAMPLES:: - sage: perm4 = polytopes.permutahedron(4) sage: perm4 A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 24 vertices From 1a82754ea33046384dbefc6045de5bef0e0a2261 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 00:18:32 +0200 Subject: [PATCH 344/665] Trac 18213: doctest fix --- src/doc/en/thematic_tutorials/polytutorial.rst | 6 +++--- src/sage/geometry/fan.py | 8 ++++---- .../geometry/hyperplane_arrangement/arrangement.py | 6 +++--- .../geometry/hyperplane_arrangement/hyperplane.py | 2 +- src/sage/geometry/integral_points.pyx | 2 +- src/sage/geometry/polyhedron/library.py | 8 ++++---- src/sage/geometry/triangulation/element.py | 12 ++++++------ src/sage/plot/graphics.py | 2 +- src/sage/plot/plot3d/shapes2.py | 2 +- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/doc/en/thematic_tutorials/polytutorial.rst b/src/doc/en/thematic_tutorials/polytutorial.rst index e60370fc85c..a74d7361d88 100644 --- a/src/doc/en/thematic_tutorials/polytutorial.rst +++ b/src/doc/en/thematic_tutorials/polytutorial.rst @@ -295,9 +295,9 @@ list of pre\-built polytopes. :: - sage: P5 = polytopes.n_cube(5) + sage: P5 = polytopes.hypercube(5) sage: P6 = polytopes.cross_polytope(3) - sage: P7 = polytopes.n_simplex(7) + sage: P7 = polytopes.simplex(7) .. end of output @@ -307,7 +307,7 @@ Let's look at a 4\-dimensional polytope. :: - sage: P8 = polytopes.n_cube(4) + sage: P8 = polytopes.hypercube(4) sage: P8.plot() Graphics3d Object diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index ca3f5e4d5ff..723a749f505 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -639,8 +639,8 @@ def FaceFan(polytope, lattice=None): sage: cuboctahed = polytopes.cuboctahedron() sage: FaceFan(cuboctahed) Rational polyhedral fan in 3-d lattice M - sage: cuboctahed.is_lattice_polytope(), cuboctahed.dilation(2).is_lattice_polytope() - (False, True) + sage: cuboctahed.is_lattice_polytope(), cuboctahed.dilation(1/2).is_lattice_polytope() + (True, False) sage: fan1 = FaceFan(cuboctahed) sage: fan2 = FaceFan(cuboctahed.dilation(2).lattice_polytope()) sage: fan1.is_equivalent(fan2) @@ -745,8 +745,8 @@ def NormalFan(polytope, lattice=None): TESTS:: - sage: cuboctahed.is_lattice_polytope(), cuboctahed.dilation(2).is_lattice_polytope() - (False, True) + sage: cuboctahed.is_lattice_polytope(), cuboctahed.dilation(1/2).is_lattice_polytope() + (True, False) sage: fan1 = NormalFan(cuboctahed) sage: fan2 = NormalFan(cuboctahed.dilation(2).lattice_polytope()) sage: fan1.is_equivalent(fan2) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 8a5649d365d..4aba8c9440f 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -83,7 +83,7 @@ Notation (v): from the bounding hyperplanes of a polyhedron:: - sage: a = polytopes.n_cube(3).hyperplane_arrangement(); a + sage: a = polytopes.cube().hyperplane_arrangement(); a Arrangement of 6 hyperplanes of dimension 3 and rank 3 sage: a.n_regions() 27 @@ -540,7 +540,7 @@ def rank(self): sage: B.rank() 2 - sage: p = polytopes.n_simplex(5) + sage: p = polytopes.simplex(5, project=True) sage: H = p.hyperplane_arrangement() sage: H.rank() 5 @@ -2095,7 +2095,7 @@ def _element_constructor_(self, *args, **kwds): sage: L._element_constructor_([[0, 1, 0], [0, 0, 1]]) Arrangement - sage: L._element_constructor(polytopes.n_cube(2)) + sage: L._element_constructor(polytopes.hypercube(2)) Arrangement <-x + 1 | -y + 1 | y + 1 | x + 1> sage: L(x, x, warn_duplicates=True) diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 3f9e05a9c8f..d73bc840925 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -452,7 +452,7 @@ def intersection(self, other): sage: h = x + y + z - 1 sage: h.intersection(x - y) A 1-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 1 line - sage: h.intersection(polytopes.n_cube(3)) + sage: h.intersection(polytopes.cube()) A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices """ from sage.geometry.polyhedron.base import is_Polyhedron diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index f9f4bf5b689..bde90c18d6d 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -494,7 +494,7 @@ def rectangular_box_points(box_min, box_max, polyhedron=None, Optionally, return the information about the saturated inequalities as well:: - sage: cube = polytopes.n_cube(3) + sage: cube = polytopes.cube() sage: cube.Hrepresentation(0) An inequality (0, 0, -1) x + 1 >= 0 sage: cube.Hrepresentation(1) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index f6dcfed1fc3..d30b7776b6c 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -117,13 +117,13 @@ def project_points(*points): a vector `v`, the projection of `v` restricted to the first `i` coordinates will be equal to the projection of the first `i+1` coordinates of `v`:: - sage: project_points([1,2]) + sage: project_points([1,2]) # abs tol 1e-15 [(-0.7071067811865475)] - sage: project_points([1,2,3]) + sage: project_points([1,2,3]) # abs tol 1e-15 [(-0.7071067811865475, -1.2247448713915892)] - sage: project_points([1,2,3,4]) + sage: project_points([1,2,3,4]) # abs tol 1e-15 [(-0.7071067811865475, -1.2247448713915892, -1.7320508075688776)] - sage: project_points([1,2,3,4,0]) + sage: project_points([1,2,3,4,0]) # abs tol 1e-15 [(-0.7071067811865475, -1.2247448713915892, -1.7320508075688776, 2.23606797749979)] Check that it is (almost) an isometry:: diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 5fad44d811a..11c8b9c0abf 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -616,7 +616,7 @@ def _boundary_simplex_dictionary(self): TESTS:: - sage: triangulation = polytopes.n_cube(2).triangulate(engine='internal') + sage: triangulation = polytopes.hypercube(2).triangulate(engine='internal') sage: triangulation._boundary_simplex_dictionary() {(0, 1): ((0, 1, 3),), (0, 2): ((0, 2, 3),), @@ -624,7 +624,7 @@ def _boundary_simplex_dictionary(self): (1, 3): ((0, 1, 3),), (2, 3): ((0, 2, 3),)} - sage: triangulation = polytopes.n_cube(3).triangulate(engine='internal') + sage: triangulation = polytopes.cube().triangulate(engine='internal') sage: triangulation._boundary_simplex_dictionary() {(0, 1, 2): ((0, 1, 2, 7),), (0, 1, 4): ((0, 1, 4, 7),), @@ -666,7 +666,7 @@ def boundary(self): EXAMPLES:: - sage: triangulation = polytopes.n_cube(3).triangulate(engine='internal') + sage: triangulation = polytopes.cube().triangulate(engine='internal') sage: triangulation (<0,1,2,7>, <0,1,4,7>, <0,2,4,7>, <1,2,3,7>, <1,4,5,7>, <2,4,6,7>) sage: triangulation.boundary() @@ -702,7 +702,7 @@ def interior_facets(self): EXAMPLES:: - sage: triangulation = polytopes.n_cube(3).triangulate(engine='internal') + sage: triangulation = polytopes.cube().triangulate(engine='internal') sage: triangulation (<0,1,2,7>, <0,1,4,7>, <0,2,4,7>, <1,2,3,7>, <1,4,5,7>, <2,4,6,7>) sage: triangulation.boundary() @@ -750,7 +750,7 @@ def normal_cone(self): EXAMPLES:: - sage: triangulation = polytopes.n_cube(2).triangulate(engine='internal') + sage: triangulation = polytopes.hypercube(2).triangulate(engine='internal') sage: triangulation (<0,1,3>, <0,2,3>) sage: N = triangulation.normal_cone(); N @@ -772,7 +772,7 @@ def normal_cone(self): TESTS:: - sage: polytopes.n_simplex(2).triangulate().normal_cone() + sage: polytopes.simplex(2).triangulate().normal_cone() 3-d cone in 3-d lattice sage: _.dual().is_trivial() True diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 0c8f61abb76..e21fc6e7585 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -3092,7 +3092,7 @@ def description(self): EXAMPLES:: - sage: print polytopes.n_cube(2).plot().description() + sage: print polytopes.hypercube(2).plot().description() Polygon defined by 4 points: [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)] Line defined by 2 points: [(-1.0, -1.0), (-1.0, 1.0)] Line defined by 2 points: [(-1.0, -1.0), (1.0, -1.0)] diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 0a789137282..eb4d3edab00 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -1055,7 +1055,7 @@ def point3d(v, size=5, **kwds): sage: print point(vector((2,3,4))) Graphics3d Object - sage: c = polytopes.n_cube(3) + sage: c = polytopes.hypercube(3) sage: v = c.vertices()[0]; v A vertex at (-1, -1, -1) sage: print point(v) From 75f0a4a3305375b9bbad62aaadb22a95bd009c31 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 00:22:43 +0200 Subject: [PATCH 345/665] Trac 18244: be more verbose in _test_enumerated_set_iter_cardinality --- src/sage/categories/finite_enumerated_sets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index b154fba2d51..03acc4f8df2 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -452,14 +452,15 @@ def _test_enumerated_set_iter_cardinality(self, **options): sage: CC._test_enumerated_set_iter_cardinality() Traceback (most recent call last): ... - AssertionError: False is not true + AssertionError: expected a Sage Integer and got 3 of type """ # isinstance with LazyImported classes is not robust from sage.rings.integer import Integer tester = self._tester(**options) if self.cardinality != self._cardinality_from_iterator: card = self.cardinality() - tester.assert_(isinstance(card, Integer)) + tester.assert_(isinstance(card, Integer), + "expected a Sage Integer and got {} of type {}".format(card,type(card))) if card <= tester._max_runs: tester.assertEqual(card, self._cardinality_from_iterator()) From 60fcedce48b8237353e72315976ed24ab7c236ca Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 00:32:14 +0200 Subject: [PATCH 346/665] Trac 18157: adding reference to the trac ticket --- src/sage/structure/coerce_actions.pyx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 87d8d7576ed..34fa435ff52 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -67,7 +67,7 @@ cdef class GenericAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: M = MatrixSpace(ZZ,2) sage: sage.structure.coerce_actions.ActedUponAction(M, Cusps, True) @@ -103,7 +103,7 @@ cdef class GenericAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to random - errors. :: + errors (see :trac:`18157`). :: sage: M = MatrixSpace(ZZ,2) @@ -180,7 +180,7 @@ def detect_element_action(Parent X, Y, bint X_on_left, X_el=None, Y_el=None): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import detect_element_action sage: ZZx = ZZ['x'] @@ -293,7 +293,8 @@ cdef class ModuleAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: + sage: from sage.structure.coerce_actions import LeftModuleAction sage: ZZx = ZZ['x'] @@ -387,7 +388,7 @@ cdef class ModuleAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import LeftModuleAction, RightModuleAction sage: ZZx = ZZ['x'] @@ -413,7 +414,7 @@ cdef class ModuleAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import LeftModuleAction sage: ZZxyz = ZZ['x,y,z'] @@ -434,7 +435,7 @@ cdef class ModuleAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import LeftModuleAction sage: ZZxyz = ZZ['x,y,z'] @@ -451,7 +452,7 @@ cdef class ModuleAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to random - errors. :: + errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import RightModuleAction @@ -548,7 +549,7 @@ cdef class LeftModuleAction(ModuleAction): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import LeftModuleAction sage: R. = QQ['x'] @@ -585,7 +586,7 @@ cdef class RightModuleAction(ModuleAction): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the domains, for otherwise they could be garbage collected, giving rise to - random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import RightModuleAction sage: R. = QQ['x'] @@ -666,7 +667,7 @@ cdef class IntegerMulAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the field ``GF(101)``, for otherwise it could be garbage collected, giving rise - to random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import IntegerMulAction sage: GF101 = GF(101) @@ -730,7 +731,7 @@ cdef class IntegerMulAction(Action): Note that coerce actions should only be used inside of the coercion model. For this test, we need to strongly reference the field ``GF(5)``, for otherwise it could be garbage collected, giving rise - to random errors. :: + random errors (see :trac:`18157`). :: sage: from sage.structure.coerce_actions import IntegerMulAction sage: GF5 = GF(5) From 5dfb8363c6fe1920dbaa09e3bae1e8f5a76be34c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 01:39:03 +0200 Subject: [PATCH 347/665] Trac 18244: fix (indirectly) cardinality in dyck_word --- src/sage/combinat/dyck_word.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index 7b4c4799235..ff49b77f0c0 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -70,7 +70,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.all import Posets -from sage.rings.all import QQ +from sage.rings.all import ZZ, QQ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.words.word import Word from sage.combinat.alternating_sign_matrix import AlternatingSignMatrices @@ -3173,10 +3173,15 @@ def __classcall_private__(cls, k1=None, k2=None, complete=True): if complete: return CompleteDyckWords_all() return DyckWords_all() + + k1 = ZZ(k1) if k1 < 0: raise ValueError("k1 (= %s) must be nonnegative" % k1) return CompleteDyckWords_size(k1) + else: + k1 = ZZ(k1) + k2 = ZZ(k2) if k1 < 0 or (k2 is not None and k2 < 0): raise ValueError("k1 (= %s) and k2 (= %s) must be nonnegative, with k1 >= k2." % (k1, k2)) if k1 < k2: @@ -3450,6 +3455,8 @@ def __init__(self, k1, k2): # Dyck paths, not words; having k1 opening parens and k2 closing # parens corresponds to paths of length k1 + k2 ending at height # k1 - k2. + k1 = ZZ(k1) + k2 = ZZ(k2) self.n = k1 + k2 self.endht = k1 - k2 @@ -3498,10 +3505,16 @@ def __init__(self, k1, k2): r""" TESTS:: + Check that :trac:`18244` is fixed:: + + sage: DyckWords(13r, 8r).cardinality() + 87210 + sage: parent(_) + Integer Ring sage: TestSuite(DyckWords(4,2)).run() """ - self.k1 = k1 - self.k2 = k2 + self.k1 = ZZ(k1) + self.k2 = ZZ(k2) DyckWords.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): From 120c1e9716324b229632a5432ff362d41e104409 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 11:13:48 +0200 Subject: [PATCH 348/665] Trac 18213: more abs tol in doctests --- src/sage/geometry/polyhedron/library.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index d30b7776b6c..b4be35b6ada 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -108,9 +108,9 @@ def project_points(*points): EXAMPLES:: sage: from sage.geometry.polyhedron.library import project_points - sage: project_points([2,-1,3,2]) + sage: project_points([2,-1,3,2]) # abs tol 1e-15 [(2.1213203435596424, -2.041241452319315, -0.577350269189626)] - sage: project_points([1,2,3],[3,3,5]) + sage: project_points([1,2,3],[3,3,5]) # abs tol 1e-15 [(-0.7071067811865475, -1.2247448713915892), (0.0, -1.6329931618554523)] These projections are compatible with the restriction. More precisely, given From d09d8a53a3b1a0c9661e3be4485c2d3ca1c0c148 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 11:14:36 +0200 Subject: [PATCH 349/665] Trac 18211: forgot a # optional in the doctest --- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 125039f89df..e227efa93b6 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -253,7 +253,7 @@ def ehrhart_polynomial(self, verbose=False, dual=None, Test bad options:: - sage: P.ehrhart_polynomial(bim_bam_boum=19) + sage: P.ehrhart_polynomial(bim_bam_boum=19) # optional - latte_int Traceback (most recent call last): ... RuntimeError: Something went wrong (see output above) when running: From ab75258e2d73ddd29ffb1aa37b4cb8b04a072f67 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 11:52:55 +0200 Subject: [PATCH 350/665] Trac 18239: faster and simpler __hash__ --- .../groups/perm_gps/permgroup_element.pyx | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 3805ce14b1f..290f5d44769 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -980,17 +980,28 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): EXAMPLES:: sage: G = SymmetricGroup(5) - sage: s = G([2,1,5,3,4]) - sage: s.tuple() - (2, 1, 5, 3, 4) - sage: hash(s) - 1592966088 # 32-bit - 2865702456085625800 # 64-bit - sage: hash(s.tuple()) - 1592966088 # 32-bit - 2865702456085625800 # 64-bit + sage: hash(G([2,1,5,3,4])) + -405124782 # 32-bit + -1701105524078393006 # 64-bit + + Check that the hash looks reasonable:: + + sage: s = set() + sage: s.update(map(hash,SymmetricGroup(1))) + sage: s.update(map(hash,SymmetricGroup(2))) + sage: s.update(map(hash,SymmetricGroup(3))) + sage: s.update(map(hash,SymmetricGroup(4))) + sage: s.update(map(hash,SymmetricGroup(5))) + sage: len(s) == 1 + 2 + 6 + 24 + 120 + True """ - return hash(tuple(self._gap_list())) + cdef size_t i + cdef long ans = self.n + for i in range(self.n): + ans = (ans ^ (self.perm[i])) * 1000003L + if ans == -1: + ans = -2 + return ans def tuple(self): """ From 06e6f47f4bc1459525e6414189add2348db1feb0 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 18 Apr 2015 12:17:38 +0200 Subject: [PATCH 351/665] Ref: start organizing the ToC of r/misc (TBI once all modules are in the manual...) --- .../en/reference/data_structures/index.rst | 1 + src/doc/en/reference/misc/index.rst | 323 +++++++++++++----- src/sage/ext/multi_modular.pyx | 2 +- src/sage/misc/cython.py | 2 +- src/sage/misc/lazy_import_cache.py | 2 + src/sage/misc/map_threaded.py | 2 +- src/sage/misc/messaging.py | 2 +- src/sage/misc/misc_c.pyx | 2 +- src/sage/misc/parser.pyx | 2 +- src/sage/misc/sage_itertools.py | 2 + src/sage/misc/search.pyx | 2 +- src/sage/rings/sum_of_squares.pyx | 2 + 12 files changed, 243 insertions(+), 101 deletions(-) diff --git a/src/doc/en/reference/data_structures/index.rst b/src/doc/en/reference/data_structures/index.rst index 0bc8339d83c..52e3280b17d 100644 --- a/src/doc/en/reference/data_structures/index.rst +++ b/src/doc/en/reference/data_structures/index.rst @@ -4,6 +4,7 @@ Data Structures .. toctree:: :maxdepth: 2 + sage/misc/binary_tree sage/data_structures/bitset sage/data_structures/bounded_integer_sequences diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 711ec63bcbc..433080546ce 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -1,120 +1,111 @@ -Miscellaneous -============= +Utilities +========= + +General Infrastructure +---------------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + + sage/misc/defaults + sage/misc/functional + sage/misc/randstate + sage/misc/prandom + sage/misc/unknown + sage/misc/exceptions + +Programming Utilities +--------------------- + +Special Base Classes, Decorators, etc. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 sage/misc/abstract_method - sage/misc/ascii_art sage/misc/bindable_class - sage/misc/cachefunc - sage/misc/weak_dict - sage/misc/c3 - sage/misc/c3_controlled sage/misc/decorators - sage/misc/classgraph - sage/misc/dev_tools - sage/misc/function_mangling - sage/misc/exceptions - sage/misc/misc - sage/misc/temporary_file sage/misc/constant_function - sage/misc/package - sage/misc/explain_pickle - sage/misc/getusage - sage/misc/mrange - sage/misc/dist - sage/misc/functional - sage/misc/html - sage/misc/table - sage/misc/log - sage/misc/persist - sage/misc/unknown - sage/misc/func_persist - sage/misc/sage_eval - sage/misc/sage_input - sage/misc/random_testing - sage/misc/sageinspect - sage/misc/sagedoc - sage/misc/edit_module - sage/rings/arith - sage/rings/sum_of_squares - sage/misc/nested_class - sage/misc/nested_class_test sage/misc/classcall_metaclass + sage/misc/method_decorator + sage/misc/object_multiplexer sage/misc/fast_methods - sage/misc/sage_unittest - sage/misc/randstate - sage/misc/cython - sage/misc/messaging - sage/misc/viewer - sage/misc/session - sage/misc/defaults - sage/ext/multi_modular - sage/ext/memory +Lists and Iteration +~~~~~~~~~~~~~~~~~~~ - sage/media/channels - sage/media/wav +.. toctree:: + :maxdepth: 1 - sage/misc/banner - sage/misc/benchmark - sage/misc/binary_tree - sage/misc/cache - sage/misc/citation - sage/misc/copying - sage/misc/cython_c sage/misc/flatten - - sage/misc/fpickle - sage/misc/inline_fortran - sage/misc/map_threaded - sage/misc/mathml - sage/misc/memory_info - sage/misc/method_decorator - sage/misc/misc_c + sage/misc/search + sage/misc/sage_itertools + sage/misc/mrange sage/misc/multireplace - sage/misc/object_multiplexer - sage/misc/pager - sage/misc/parser - sage/misc/prandom - sage/misc/python + sage/misc/map_threaded + +Integer Arithmetic +~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/rings/sum_of_squares + sage/ext/multi_modular + sage/rings/arith + +File and OS Access +~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/temporary_file sage/misc/remote_file - sage/misc/reset - sage/misc/sage_itertools + sage/misc/messaging sage/misc/sage_ostools - sage/misc/search - sage/misc/sh - sage/misc/stopgap - sage/misc/superseded -Profiling and Performance Testing ---------------------------------- +Database Access +~~~~~~~~~~~~~~~ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - sage/misc/sage_timeit - sage/misc/sage_timeit_class - sage/misc/profiler - sage/misc/gperftools + sage/databases/sql_db +Media +~~~~~ -LaTeX ------ +.. toctree:: + :maxdepth: 1 + + sage/media/channels + sage/media/wav + +Warnings +~~~~~~~~ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - sagetex - sage/misc/latex - sage/misc/latex_macros + sage/misc/stopgap + sage/misc/superseded + +Miscellaneous Useful Functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/misc + sage/misc/misc_c Lazyness --------- +~~~~~~~~ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 sage/misc/lazy_attribute sage/misc/lazy_format @@ -123,11 +114,21 @@ Lazyness sage/misc/lazy_import_cache sage/misc/lazy_string +Caching +~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/cache + sage/misc/cachefunc + sage/misc/weak_dict + Fast Expression Evaluation --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 sage/ext/fast_callable sage/ext/fast_eval @@ -143,12 +144,146 @@ Fast Expression Evaluation .. sage/ext/interpreters/wrapper_rdf .. sage/ext/interpreters/wrapper_rr -Databases ---------- +Code Evaluation +--------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - sage/databases/sql_db + sage/misc/cython_c + sage/misc/cython + sage/misc/inline_fortran + sage/misc/parser + sage/misc/python + sage/misc/sage_eval + sage/misc/sh + +Formatted Output +---------------- + +Formatted Output +~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/ascii_art + sage/misc/sage_input + sage/misc/table + +HTML and MathML +~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/html + sage/misc/mathml + +LaTeX +~~~~~ + +.. toctree:: + :maxdepth: 1 + + sagetex + sage/misc/latex + sage/misc/latex_macros + +Saving and Loading Sage Objects +------------------------------- + +.. toctree:: + :maxdepth: 1 + + sage/misc/func_persist + sage/misc/persist + sage/misc/fpickle + sage/misc/explain_pickle + sage/misc/nested_class + sage/misc/session + +Interactive Usage Support +------------------------- + +Interactive Sage Sessions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/log + sage/misc/banner + sage/misc/reset + sage/misc/viewer + sage/misc/pager + sage/misc/sagedoc + +Distribution +~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/package + sage/misc/dist + +Credits +~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/citation + sage/misc/copying + +Development Tools +----------------- + +Testing +~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/sage_unittest + sage/misc/random_testing + sage/misc/nested_class_test + +Benchmarking and Profiling +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/benchmark + sage/misc/sage_timeit + sage/misc/sage_timeit_class + sage/misc/profiler + sage/misc/gperftools + +Miscellaneous Inspection and Development Tools +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/misc/sageinspect + sage/misc/edit_module + sage/misc/getusage + sage/misc/classgraph + sage/misc/dev_tools + sage/misc/function_mangling + sage/misc/memory_info + +Low-Level Utilities +------------------- + +.. toctree:: + :maxdepth: 1 + + sage/ext/memory + sage/misc/c3 + sage/misc/c3_controlled .. include:: ../footer.txt diff --git a/src/sage/ext/multi_modular.pyx b/src/sage/ext/multi_modular.pyx index 90d8ced9d05..52a5e2f7476 100644 --- a/src/sage/ext/multi_modular.pyx +++ b/src/sage/ext/multi_modular.pyx @@ -1,5 +1,5 @@ """ -Utility classes for multi-modular algorithms. +Utility classes for multi-modular algorithms """ ###################################################################### diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 5094c3c2143..7a6d536fb2e 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -1,5 +1,5 @@ """ -Cython -- C-Extensions for Python +Cython support functions AUTHORS: diff --git a/src/sage/misc/lazy_import_cache.py b/src/sage/misc/lazy_import_cache.py index cbd1289a178..a69a9102a08 100644 --- a/src/sage/misc/lazy_import_cache.py +++ b/src/sage/misc/lazy_import_cache.py @@ -1,4 +1,6 @@ """ +Lazy import cache + This is a pure Python file with no dependencies so it can be used in setup.py. """ diff --git a/src/sage/misc/map_threaded.py b/src/sage/misc/map_threaded.py index c04841374ec..cc8f8f0a3dd 100644 --- a/src/sage/misc/map_threaded.py +++ b/src/sage/misc/map_threaded.py @@ -1,5 +1,5 @@ """ -The threaded map function. +Threaded map function """ def map_threaded(function, sequence): diff --git a/src/sage/misc/messaging.py b/src/sage/misc/messaging.py index 477c8c1283e..b08e1724e5a 100644 --- a/src/sage/misc/messaging.py +++ b/src/sage/misc/messaging.py @@ -1,5 +1,5 @@ """ -Message delivery. +Message delivery Various interfaces to messaging services. Currently: diff --git a/src/sage/misc/misc_c.pyx b/src/sage/misc/misc_c.pyx index 9c1490952bf..91fd04d6ea1 100644 --- a/src/sage/misc/misc_c.pyx +++ b/src/sage/misc/misc_c.pyx @@ -1,5 +1,5 @@ """ -Miscellaneous functions +Miscellaneous functions (Cython) This file contains support for products, running totals, balanced sums, and bitset tests. diff --git a/src/sage/misc/parser.pyx b/src/sage/misc/parser.pyx index 3d08d1ae8df..b529279fe51 100644 --- a/src/sage/misc/parser.pyx +++ b/src/sage/misc/parser.pyx @@ -1,5 +1,5 @@ """ -This module provides a parser for symbolic equations and expressions. +A parser for symbolic equations and expressions It is both safer and more powerful than using Python's eval, as one has complete control over what names are used (including dynamically creating diff --git a/src/sage/misc/sage_itertools.py b/src/sage/misc/sage_itertools.py index 6b2c78c2713..c7d975b98b0 100644 --- a/src/sage/misc/sage_itertools.py +++ b/src/sage/misc/sage_itertools.py @@ -1,4 +1,6 @@ """ +Iterators + Miscellaneous functions which should eventually be moved upstream into Python's standard itertools module. diff --git a/src/sage/misc/search.pyx b/src/sage/misc/search.pyx index 233b5043fa4..92b48eaf688 100644 --- a/src/sage/misc/search.pyx +++ b/src/sage/misc/search.pyx @@ -1,5 +1,5 @@ """ -Searching a sorted list. +Searching a sorted list This is like the bisect library module, but also returns whether or not the element is in the list, which saves having to do an diff --git a/src/sage/rings/sum_of_squares.pyx b/src/sage/rings/sum_of_squares.pyx index 926b441c1c4..8dcacc2f6fe 100644 --- a/src/sage/rings/sum_of_squares.pyx +++ b/src/sage/rings/sum_of_squares.pyx @@ -1,4 +1,6 @@ r""" +Fast decomposition of small integers into sums of squares + Implement fast version of decomposition of (small) integers into sum of squares by direct method not relying on factorisation. From 762b3e02dbffa614c937965978be65e0374c58c2 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 12:34:58 +0200 Subject: [PATCH 352/665] Trac 18239: fix doctests --- .../en/thematic_tutorials/group_theory.rst | 99 ++++++++++++--- src/sage/algebras/group_algebra.py | 20 +-- src/sage/categories/enumerated_sets.py | 8 +- src/sage/categories/groups.py | 72 +++++------ src/sage/categories/modules_with_basis.py | 2 +- src/sage/combinat/symmetric_group_algebra.py | 10 +- src/sage/combinat/tutorial.py | 3 +- src/sage/geometry/fan_isomorphism.py | 4 +- src/sage/geometry/lattice_polytope.py | 8 +- src/sage/graphs/generic_graph.py | 14 +-- src/sage/groups/perm_gps/permgroup.py | 11 +- .../groups/perm_gps/permgroup_element.pyx | 6 +- src/sage/groups/perm_gps/permgroup_named.py | 4 +- src/sage/matrix/operation_table.py | 118 +++++++++--------- src/sage/rings/number_field/number_field.py | 2 +- 15 files changed, 219 insertions(+), 162 deletions(-) diff --git a/src/doc/en/thematic_tutorials/group_theory.rst b/src/doc/en/thematic_tutorials/group_theory.rst index 4519187cd6c..5fd024692ff 100644 --- a/src/doc/en/thematic_tutorials/group_theory.rst +++ b/src/doc/en/thematic_tutorials/group_theory.rst @@ -413,7 +413,18 @@ The command :: sage: H = DihedralGroup(6) sage: H.list() - [(), (2,6)(3,5), (1,2)(3,6)(4,5), (1,2,3,4,5,6), (1,3)(4,6), (1,3,5)(2,4,6), (1,4)(2,3)(5,6), (1,4)(2,5)(3,6), (1,5)(2,4), (1,5,3)(2,6,4), (1,6,5,4,3,2), (1,6)(2,5)(3,4)] + [(), + (1,6)(2,5)(3,4), + (1,2,3,4,5,6), + (1,5)(2,4), + (2,6)(3,5), + (1,3,5)(2,4,6), + (1,4)(2,3)(5,6), + (1,6,5,4,3,2), + (1,4)(2,5)(3,6), + (1,2)(3,6)(4,5), + (1,5,3)(2,6,4), + (1,3)(4,6)] will return all of the elements of `H` in a fixed order as a Python list. Indexing (``[ ]``) can be used to extract the individual @@ -422,7 +433,7 @@ list begins at zero. :: sage: H = DihedralGroup(6) sage: elements = H.list() - sage: elements[3] + sage: elements[2] (1,2,3,4,5,6) @@ -436,17 +447,18 @@ The command :: * a b c d e f g h i j k l +------------------------ a| a b c d e f g h i j k l - b| b a d c f e h g j i l k - c| c k a e d g f i h l b j - d| d l b f c h e j g k a i - e| e j k g a i d l f b c h - f| f i l h b j c k e a d g - g| g h j i k l a b d c e f - h| h g i j l k b a c d f e - i| i f h l j b k c a e g d - j| j e g k i a l d b f h c - k| k c e a g d i f l h j b - l| l d f b h c j e k g i a + b| b a e h c j k d l f g i + c| c d f g b i l a k e h j + d| d c b a f e h g j i l k + e| e h j k a l i b g c d f + f| f g i l d k j c h b a e + g| g f d c i b a l e k j h + h| h e a b j c d k f l i g + i| i l k j g h e f a d c b + j| j k l i h g f e d a b c + k| k j h e l a b i c g f d + l| l i g f k d c j b h e a + will construct the Cayley table (or "multiplication table") of `H`. By default the table uses lowercase Latin letters to name the elements @@ -459,8 +471,7 @@ element named ``e``:: sage: T = H.cayley_table() sage: headings = T.row_keys() sage: headings[4] - (1,3)(4,6) - + (2,6)(3,5) Center ------ @@ -511,7 +522,7 @@ In more mathematical notation, we might write sage: sigma = G("(1,2,3) (4,5)") sage: H = G.subgroup([sigma]) sage: H.list() - [(), (4,5), (1,2,3), (1,2,3)(4,5), (1,3,2), (1,3,2)(4,5)] + [(), (1,2,3)(4,5), (1,3,2), (4,5), (1,2,3), (1,3,2)(4,5)] Experiment by trying different permutations for ``sigma`` and observing the effect on ``H``. @@ -565,7 +576,11 @@ subgroup:: sage: rho = C20("(1,17,13,9,5)(2,18,14,10,6)(3,19,15,11,7)(4,20,16,12,8)") sage: H = C20.subgroup([rho]) sage: H.list() - [(), (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20), (1,9,17,5,13)(2,10,18,6,14)(3,11,19,7,15)(4,12,20,8,16), (1,13,5,17,9)(2,14,6,18,10)(3,15,7,19,11)(4,16,8,20,12), (1,17,13,9,5)(2,18,14,10,6)(3,19,15,11,7)(4,20,16,12,8)] + [(), + (1,17,13,9,5)(2,18,14,10,6)(3,19,15,11,7)(4,20,16,12,8), + (1,13,5,17,9)(2,14,6,18,10)(3,15,7,19,11)(4,16,8,20,12), + (1,9,17,5,13)(2,10,18,6,14)(3,11,19,7,15)(4,12,20,8,16), + (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)] For a cyclic group, the following command will list *all* of the subgroups. :: @@ -725,7 +740,30 @@ entire symmetry group. Use :: sage: cube = PermutationGroup(["(3,2,6,7)(4,1,5,8)", ....: "(1,2,6,5)(4,3,7,8)", "(1,2,3,4)(5,6,7,8)"]) sage: cube.list() - [(), (2,4,5)(3,8,6), (2,5,4)(3,6,8), (1,2)(3,5)(4,6)(7,8), (1,2,3,4)(5,6,7,8), (1,2,6,5)(3,7,8,4), (1,3,6)(4,7,5), (1,3)(2,4)(5,7)(6,8), (1,3,8)(2,7,5), (1,4,3,2)(5,8,7,6), (1,4,8,5)(2,3,7,6), (1,4)(2,8)(3,5)(6,7), (1,5,6,2)(3,4,8,7), (1,5,8,4)(2,6,7,3), (1,5)(2,8)(3,7)(4,6), (1,6,3)(4,5,7), (1,6)(2,5)(3,8)(4,7), (1,6,8)(2,7,4), (1,7)(2,3)(4,6)(5,8), (1,7)(2,6)(3,5)(4,8), (1,7)(2,8)(3,4)(5,6), (1,8,6)(2,4,7), (1,8,3)(2,5,7), (1,8)(2,7)(3,6)(4,5)] + [(), + (1,2,3,4)(5,6,7,8), + (1,2,6,5)(3,7,8,4), + (1,5,8,4)(2,6,7,3), + (1,6,8)(2,7,4), + (1,3,8)(2,7,5), + (1,6,3)(4,5,7), + (1,6)(2,5)(3,8)(4,7), + (2,5,4)(3,6,8), + (1,3)(2,4)(5,7)(6,8), + (1,8)(2,7)(3,6)(4,5), + (1,7)(2,3)(4,6)(5,8), + (1,5,6,2)(3,4,8,7), + (1,7)(2,6)(3,5)(4,8), + (1,7)(2,8)(3,4)(5,6), + (1,4,3,2)(5,8,7,6), + (1,4)(2,8)(3,5)(6,7), + (1,5)(2,8)(3,7)(4,6), + (1,4,8,5)(2,3,7,6), + (1,2)(3,5)(4,6)(7,8), + (1,8,6)(2,4,7), + (1,3,6)(4,7,5), + (2,4,5)(3,8,6), + (1,8,3)(2,5,7)] A cube has four distinct diagonals (joining opposite vertices through the center of the cube). Each symmetry of the cube will cause the @@ -751,7 +789,30 @@ two opposite faces) can be used as generators of the symmetry group:: sage: cubeface = PermutationGroup(["(1,3,2,5)", "(1,4,2,6)", "(3,4,5,6)"]) sage: cubeface.list() - [(), (3,4,5,6), (3,5)(4,6), (3,6,5,4), (1,2)(4,6), (1,2)(3,4)(5,6), (1,2)(3,5), (1,2)(3,6)(4,5), (1,3)(2,5)(4,6), (1,3,2,5), (1,3,4)(2,5,6), (1,3,6)(2,5,4), (1,4,3)(2,6,5), (1,4,5)(2,6,3), (1,4,2,6), (1,4)(2,6)(3,5), (1,5,2,3), (1,5)(2,3)(4,6), (1,5,6)(2,3,4), (1,5,4)(2,3,6), (1,6,3)(2,4,5), (1,6,5)(2,4,3), (1,6,2,4), (1,6)(2,4)(3,5)] + [(), + (3,4,5,6), + (1,4,2,6), + (1,3,2,5), + (1,3,4)(2,5,6), + (1,3,6)(2,5,4), + (1,2)(3,5), + (1,4,5)(2,6,3), + (1,5,6)(2,3,4), + (3,5)(4,6), + (1,2)(4,6), + (1,5,2,3), + (1,6)(2,4)(3,5), + (1,4)(2,6)(3,5), + (1,2)(3,4)(5,6), + (1,3)(2,5)(4,6), + (3,6,5,4), + (1,5)(2,3)(4,6), + (1,6,2,4), + (1,2)(3,6)(4,5), + (1,6,3)(2,4,5), + (1,6,5)(2,4,3), + (1,5,4)(2,3,6), + (1,4,3)(2,6,5)] Again, this subgroup of `S_6` is "same as" the full symmetric group, `S_4`:: diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 0203f45c41c..ccd51a121e6 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -9,9 +9,9 @@ sage: D4 = DihedralGroup(4) sage: kD4 = GroupAlgebra(D4, GF(7)) sage: a = kD4.an_element(); a - () + 2*(2,4) + 3*(1,2)(3,4) + (1,2,3,4) + () + 4*(1,2,3,4) + 2*(1,4)(2,3) sage: a * a - (1,2)(3,4) + (1,2,3,4) + 3*(1,3) + (1,3)(2,4) + 6*(1,4,3,2) + 2*(1,4)(2,3) + 5*() + (2,4) + (1,2,3,4) + (1,3) + 2*(1,3)(2,4) + 4*(1,4)(2,3) Given the group and the base ring, the corresponding group algebra is unique:: @@ -44,11 +44,11 @@ sage: a = A.an_element(); a () + 3*(3,4) + 3*(1,2) sage: b = B.an_element(); b - () + 2*(3,4) + 3*(2,3) + (1,2,3,4) + () + 2*(1,2) + 4*(1,2,3,4) sage: B(a) () + 3*(3,4) + 3*(1,2) sage: a * b # a is automatically converted to an element of B - 7*() + 5*(3,4) + 3*(2,3) + 9*(2,3,4) + 3*(1,2) + 6*(1,2)(3,4) + 3*(1,2,3) + (1,2,3,4) + 9*(1,3,2) + 3*(1,3,4) + 7*() + 3*(3,4) + 5*(1,2) + 6*(1,2)(3,4) + 12*(1,2,3) + 4*(1,2,3,4) + 12*(1,3,4) sage: parent(a * b) Group algebra of group "Symmetric group of order 4! as a permutation group" over base ring Rational Field @@ -64,16 +64,18 @@ sage: A(b) Traceback (most recent call last): ... - TypeError: Don't know how to create an element of Group algebra of group "Dihedral group of order 4 as a permutation group" over base ring Integer Ring from () + 2*(3,4) + 3*(2,3) + (1,2,3,4) + TypeError: Don't know how to create an element of Group algebra of group + "Dihedral group of order 4 as a permutation group" over base ring Integer + Ring from () + 2*(1,2) + 4*(1,2,3,4) Group algebras have the structure of Hopf algebras:: sage: a = kD4.an_element(); a - () + 2*(2,4) + 3*(1,2)(3,4) + (1,2,3,4) + () + 4*(1,2,3,4) + 2*(1,4)(2,3) sage: a.antipode() - () + 2*(2,4) + 3*(1,2)(3,4) + (1,4,3,2) + () + 4*(1,4,3,2) + 2*(1,4)(2,3) sage: a.coproduct() - () # () + 2*(2,4) # (2,4) + 3*(1,2)(3,4) # (1,2)(3,4) + (1,2,3,4) # (1,2,3,4) + () # () + 4*(1,2,3,4) # (1,2,3,4) + 2*(1,4)(2,3) # (1,4)(2,3) .. note:: @@ -334,7 +336,7 @@ def algebra_generators(self): sage: A = GroupAlgebra(DihedralGroup(3), QQ); A Group algebra of group "Dihedral group of order 6 as a permutation group" over base ring Rational Field sage: A.algebra_generators() - Finite family {(1,2,3): (1,2,3), (1,3): (1,3)} + Finite family {(1,3): (1,3), (1,2,3): (1,2,3)} """ from sage.sets.family import Family return Family(self._group.gens(), self.monomial) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index b946290f929..a4bfebd1380 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -549,9 +549,9 @@ def map(self, f, name=None): sage: R.cardinality() 6 sage: R.list() - [[], [2], [1], [2, 1], [1, 2], [1, 2, 1]] + [[], [1], [2, 1], [1, 2], [2], [1, 2, 1]] sage: [ r for r in R] - [[], [2], [1], [2, 1], [1, 2], [1, 2, 1]] + [[], [1], [2, 1], [1, 2], [2], [1, 2, 1]] .. warning:: @@ -560,9 +560,9 @@ def map(self, f, name=None): sage: P = SymmetricGroup(3) sage: P.list() - [(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)] + [(), (1,2), (1,2,3), (1,3,2), (2,3), (1,3)] sage: P.map(attrcall('length')).list() - [0, 1, 1, 2, 2, 3] + [0, 1, 2, 2, 1, 3] .. warning:: diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 785d81afc12..e884c3a3220 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -245,22 +245,22 @@ def cayley_table(self, names='letters', elements=None): sage: G = DiCyclicGroup(3) sage: T = G.cayley_table() sage: T.column_keys() - ((), (5,6,7), (5,7,6)...(1,4,2,3)(5,7)) + ((), (1,3,2,4)(5,7), ..., (1,2)(3,4)(5,7,6)) sage: T * a b c d e f g h i j k l +------------------------ a| a b c d e f g h i j k l - b| b c a e f d i g h l j k - c| c a b f d e h i g k l j - d| d e f a b c j k l g h i - e| e f d b c a l j k i g h - f| f d e c a b k l j h i g - g| g h i j k l d e f a b c - h| h i g k l j f d e c a b - i| i g h l j k e f d b c a - j| j k l g h i a b c d e f - k| k l j h i g c a b f d e - l| l j k i g h b c a e f d + b| b e f j i h d k a l c g + c| c g d e h b k l j f i a + d| d k e h l g i a f b j c + e| e i h l a k j c b g f d + f| f d j i k e c g l h a b + g| g h b f j l e i c a d k + h| h j l a c i f d g k b e + i| i a k g b c l f e d h j + j| j c i k g d a b h e l f + k| k l g b f a h j d c e i + l| l f a c d j b e k i g h :: @@ -316,18 +316,18 @@ def cayley_table(self, names='letters', elements=None): :: sage: G=QuaternionGroup() - sage: names=['1', 'I', '-1', '-I', 'J', '-K', '-J', 'K'] + sage: names=['1', 'I', 'J', '-1', '-K', 'K', '-I', '-J'] sage: G.cayley_table(names=names) - * 1 I -1 -I J -K -J K + * 1 I J -1 -K K -I -J +------------------------ - 1| 1 I -1 -I J -K -J K - I| I -1 -I 1 K J -K -J - -1| -1 -I 1 I -J K J -K - -I| -I 1 I -1 -K -J K J - J| J -K -J K -1 -I 1 I - -K| -K -J K J I -1 -I 1 - -J| -J K J -K 1 I -1 -I - K| K J -K -J -I 1 I -1 + 1| 1 I J -1 -K K -I -J + I| I -1 K -I J -J 1 -K + J| J -K -1 -J -I I K 1 + -1| -1 -I -J 1 K -K I J + -K| -K -J I K -1 1 J -I + K| K J -I -K 1 -1 -J I + -I| -I 1 -K I -J J -1 K + -J| -J K 1 J I -I -K -1 :: @@ -388,21 +388,21 @@ class provides even greater flexibility, including changing . a b c d e f g h i j k l +------------------------ a| a a a a a a a a a a a a - b| a a a a a a c c c c c c - c| a a a a a a b b b b b b - d| a a a a a a a a a a a a - e| a a a a a a c c c c c c - f| a a a a a a b b b b b b - g| a b c a b c a c b a c b - h| a b c a b c b a c b a c - i| a b c a b c c b a c b a - j| a b c a b c a c b a c b - k| a b c a b c b a c b a c - l| a b c a b c c b a c b a + b| a a h d a d h h a h d d + c| a d a a a d d a d d d a + d| a h a a a h h a h h h a + e| a a a a a a a a a a a a + f| a h h d a a d h h d a d + g| a d h d a h a h d a h d + h| a d a a a d d a d d d a + i| a a h d a d h h a h d d + j| a d h d a h a h d a h d + k| a h h d a a d h h d a d + l| a h a a a h h a h h h a sage: trans = T.translation() - sage: comm = [trans['a'], trans['b'],trans['c']] + sage: comm = [trans['a'], trans['d'],trans['h']] sage: comm - [(), (5,6,7), (5,7,6)] + [(), (5,7,6), (5,6,7)] sage: P=G.cayley_table(elements=comm) sage: P * a b c @@ -654,7 +654,7 @@ def algebra_generators(self): EXAMPLES:: sage: GroupAlgebras(QQ).example(AlternatingGroup(10)).algebra_generators() - Finite family {(1,2,3,4,5,6,7,8,9): B[(1,2,3,4,5,6,7,8,9)], (8,9,10): B[(8,9,10)]} + Finite family {(8,9,10): B[(8,9,10)], (1,2,3,4,5,6,7,8,9): B[(1,2,3,4,5,6,7,8,9)]} """ from sage.sets.family import Family return Family(self.group().gens(), self.term) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 0f7f6c75d98..9d6b0be2bd6 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1219,7 +1219,7 @@ def _an_element_(self): sage: B = HopfAlgebrasWithBasis(QQ).example(); B An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field sage: A.an_element(), B.an_element() - (2*B[word: ] + 2*B[word: a] + 3*B[word: b], B[()] + 2*B[(2,3)] + 3*B[(1,2)] + B[(1,2,3)]) + (2*B[word: ] + 2*B[word: a] + 3*B[word: b], B[()] + 4*B[(1,2,3)] + 2*B[(1,3)]) sage: cartesian_product((A, B, A)).an_element() # indirect doctest 2*B[(0, word: )] + 2*B[(0, word: a)] + 3*B[(0, word: b)] """ diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 0dc3b28f5e6..a354f84a9b5 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -90,7 +90,7 @@ def SymmetricGroupAlgebra(R, W): sage: SGA.group() Symmetric group of order 4! as a permutation group sage: SGA.an_element() - () + 2*(3,4) + 3*(2,3) + (1,2,3,4) + () + 2*(1,2) + 4*(1,2,3,4) sage: SGA = SymmetricGroupAlgebra(QQ, WeylGroup(["A",3], prefix='s')); SGA Symmetric group algebra of order 4 over Rational Field @@ -221,7 +221,7 @@ def __init__(self, R, W): sage: G = SymmetricGroup(4).algebra(QQ) sage: S = SymmetricGroupAlgebra(QQ,4) sage: S(G.an_element()) - [1, 2, 3, 4] + 2*[1, 2, 4, 3] + 3*[1, 3, 2, 4] + [2, 3, 4, 1] + [1, 2, 3, 4] + 2*[2, 1, 3, 4] + 4*[2, 3, 4, 1] sage: G(S.an_element()) () + 2*(3,4) + 3*(2,3) + (1,4,3,2) """ @@ -672,7 +672,7 @@ def retract_plain(self, f, m): sage: G = SymmetricGroup(4).algebra(QQ) sage: G.retract_plain(G.an_element(), 3) - () + 3*(2,3) + () + 2*(1,2) .. SEEALSO:: @@ -738,7 +738,7 @@ def retract_direct_product(self, f, m): sage: G = SymmetricGroup(4).algebra(QQ) sage: G.retract_direct_product(G.an_element(), 3) - () + 3*(2,3) + () + 2*(1,2) .. SEEALSO:: @@ -801,7 +801,7 @@ def retract_okounkov_vershik(self, f, m): sage: G = SymmetricGroup(4).algebra(QQ) sage: G.retract_okounkov_vershik(G.an_element(), 3) - 3*() + 3*(2,3) + (1,2,3) + () + 2*(1,2) + 4*(1,2,3) .. SEEALSO:: diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index fc933b4df6e..8371447c910 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -900,8 +900,7 @@ sage: G.cardinality() 8 sage: G.list() - [(), (2,4), (1,2)(3,4), (1,2,3,4), (1,3), (1,3)(2,4), - (1,4,3,2), (1,4)(2,3)] + [(), (1,4)(2,3), (1,2,3,4), (1,3)(2,4), (1,3), (2,4), (1,4,3,2), (1,2)(3,4)] or the algebra of `2\times 2` matrices over the finite field `\ZZ/2\ZZ`:: diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index 6a20f83f7f7..51bdd5f6f88 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -86,8 +86,8 @@ def fan_isomorphism_generator(fan1, fan2): sage: from sage.geometry.fan_isomorphism import fan_isomorphism_generator sage: tuple( fan_isomorphism_generator(fan, fan) ) ( - [1 0] [0 1] [ 1 0] [-1 -1] [ 0 1] [-1 -1] - [0 1], [1 0], [-1 -1], [ 1 0], [-1 -1], [ 0 1] + [1 0] [0 1] [ 1 0] [ 0 1] [-1 -1] [-1 -1] + [0 1], [1 0], [-1 -1], [-1 -1], [ 1 0], [ 0 1] ) sage: m1 = matrix([(1, 0), (0, -5), (-3, 4)]) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 1604edd8f5e..f74022b973d 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2688,12 +2688,8 @@ def _palp_PM_max(self, check=False): [(), ()], [(2,3), (2,3)]] sage: PM_max.automorphisms_of_rows_and_columns() - [((), ()), - ((2,3), (2,3)), - ((1,2), (1,2)), - ((1,2,3), (1,2,3)), - ((1,3,2), (1,3,2)), - ((1,3), (1,3))] + [((), ()), ((2,3), (2,3)), ((1,2), (1,2)), + ((1,3,2), (1,3,2)), ((1,2,3), (1,2,3)), ((1,3), (1,3))] sage: PMs = [i._palp_PM_max(check=True) ....: for i in ReflexivePolytopes(2)] # long time sage: all(len(i) == len(j.automorphisms_of_rows_and_columns()) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f06fd429f7d..4f77c71b9b6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14722,7 +14722,7 @@ def _color_by_label(self, format='hex', as_function=False, default_color = "blac sage: f = G._color_by_label(as_function=True) sage: [f(1), f(2), f(3)] - ['#00ff00', '#ff0000', '#0000ff'] + ['#ff0000', '#00ff00', '#0000ff'] sage: f = G._color_by_label({1: "blue", 2: "red", 3: "green"}, as_function=True) sage: [f(1), f(2), f(3)] ['blue', 'red', 'green'] @@ -14736,14 +14736,14 @@ def _color_by_label(self, format='hex', as_function=False, default_color = "blac The default output is a dictionary assigning edges to colors:: sage: G._color_by_label() - {'#0000ff': [((1,4,3,2), (1,3,2), 3), ... ((1,2)(3,4), (1,2), 3)], - '#00ff00': [((1,4,3,2), (1,4,3), 1), ... ((1,2)(3,4), (3,4), 1)], - '#ff0000': [((1,4,3,2), (1,4,2), 2), ... ((1,2)(3,4), (1,3,4,2), 2)]} + {'#0000ff': [((1,3,2,4), (1,4)(2,3), 3), ..., ((1,3), (1,4,3), 3)], + '#00ff00': [((1,3,2,4), (1,2,4), 2), ..., ((1,3), (1,2,3), 2)], + '#ff0000': [((1,3,2,4), (1,3)(2,4), 1), ..., ((1,3), (1,3,2), 1)]} sage: G._color_by_label({1: "blue", 2: "red", 3: "green"}) - {'blue': [((1,4,3,2), (1,4,3), 1), ... ((1,2)(3,4), (3,4), 1)], - 'green': [((1,4,3,2), (1,3,2), 3), ... ((1,2)(3,4), (1,2), 3)], - 'red': [((1,4,3,2), (1,4,2), 2), ... ((1,2)(3,4), (1,3,4,2), 2)]} + {'blue': [((1,3,2,4), (1,3)(2,4), 1), ..., ((1,3), (1,3,2), 1)], + 'green': [((1,3,2,4), (1,4)(2,3), 3), ..., ((1,3), (1,4,3), 3)], + 'red': [((1,3,2,4), (1,2,4), 2), ..., ((1,3), (1,2,3), 2)]} TESTS: diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index d60fb1ccd3d..30a045636ab 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -711,11 +711,10 @@ def list(self): sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.list() - [(), (1,2), (1,2,3,4), (1,3,4), (2,3,4), (1,3)(2,4), - (1,4,3,2), (1,3,2,4), (1,2,4,3), (1,3,4,2), - (1,4,2,3), (2,4,3), (1,4,3), (1,3,2), (1,4)(2,3), - (1,4,2), (3,4), (2,4), (1,4), (2,3), (1,3), (1,2,3), - (1,2,4), (1,2)(3,4)] + [(), (1,2), (1,2,3,4), (1,3)(2,4), (1,3,4), (2,3,4), (1,4,3,2), + (1,3,2,4), (1,3,4,2), (1,2,4,3), (1,4,2,3), (2,4,3), (1,4,3), + (1,4)(2,3), (1,4,2), (1,3,2), (1,3), (3,4), (2,4), (1,4), (2,3), + (1,2)(3,4), (1,2,3), (1,2,4)] sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b')); G Permutation Group with generators [('a','b')] @@ -3057,7 +3056,7 @@ def cosets(self, S, side='right'): need for sorting the elements of the cosets. :: sage: G = DihedralGroup(8) - sage: quarter_turn = G.list()[5]; quarter_turn + sage: quarter_turn = G('(1,3,5,7)(2,4,6,8)'); quarter_turn (1,3,5,7)(2,4,6,8) sage: S = G.subgroup([quarter_turn]) sage: rc = G.cosets(S); rc diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 290f5d44769..c0e2c7e81db 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -975,14 +975,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): def __hash__(self): """ - Return hash of this permutation. + Return a hash for this permutation. EXAMPLES:: sage: G = SymmetricGroup(5) sage: hash(G([2,1,5,3,4])) - -405124782 # 32-bit - -1701105524078393006 # 64-bit + -1203337681 # 32-bit + -1527414595000039889 # 64-bit Check that the hash looks reasonable:: diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 05025a5e44f..2a3a6f9c12b 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1277,8 +1277,8 @@ def __init__(self, n): sage: DihedralGroup(5).gens() [(1,2,3,4,5), (1,5)(2,4)] sage: list(DihedralGroup(5)) - [(), (1,5)(2,4), (1,2,3,4,5), (2,5)(3,4), (1,4)(2,3), (1,3,5,2,4), - (1,5,4,3,2), (1,4,2,5,3), (1,2)(3,5), (1,3)(4,5)] + [(), (1,5)(2,4), (1,2,3,4,5), (1,4)(2,3), (1,3,5,2,4), (2,5)(3,4), + (1,3)(4,5), (1,5,4,3,2), (1,4,2,5,3), (1,2)(3,5)] sage: G = DihedralGroup(6) sage: G.order() diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 02a743cdd74..696dba2972e 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -78,10 +78,10 @@ class OperationTable(SageObject): * a b c d e f +------------ a| a b c d e f - b| b a d c f e - c| c e a f b d - d| d f b e a c - e| e c f a d b + b| b a f e d c + c| c e d a f b + d| d f a c b e + e| e c b f a d f| f d e b c a With two operations present, we can specify which operation we @@ -109,33 +109,33 @@ class OperationTable(SageObject): * aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb +------------------------------------------------------------------------------------ aa| aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb - ab| ab aa ad ac af ae ah ag aj ai al ak an am ap ao ar aq at as av au ax aw az ay bb ba - ac| ac ba aa ae ad ag af ai ah ak aj am al ao an aq ap as ar au at aw av ay ax bb ab az - ad| ad bb ab af ac ah ae aj ag al ai an ak ap am ar ao at aq av as ax au az aw ba aa ay - ae| ae az ba ag aa ai ad ak af am ah ao aj aq al as an au ap aw ar ay at bb av ab ac ax - af| af ay bb ah ab aj ac al ae an ag ap ai ar ak at am av ao ax aq az as ba au aa ad aw - ag| ag ax az ai ba ak aa am ad ao af aq ah as aj au al aw an ay ap bb ar ab at ac ae av - ah| ah aw ay aj bb al ab an ac ap ae ar ag at ai av ak ax am az ao ba aq aa as ad af au - ai| ai av ax ak az am ba ao aa aq ad as af au ah aw aj ay al bb an ab ap ac ar ae ag at - aj| aj au aw al ay an bb ap ab ar ac at ae av ag ax ai az ak ba am aa ao ad aq af ah as - ak| ak at av am ax ao az aq ba as aa au ad aw af ay ah bb aj ab al ac an ae ap ag ai ar - al| al as au an aw ap ay ar bb at ab av ac ax ae az ag ba ai aa ak ad am af ao ah aj aq - am| am ar at ao av aq ax as az au ba aw aa ay ad bb af ab ah ac aj ae al ag an ai ak ap - an| an aq as ap au ar aw at ay av bb ax ab az ac ba ae aa ag ad ai af ak ah am aj al ao - ao| ao ap ar aq at as av au ax aw az ay ba bb aa ab ad ac af ae ah ag aj ai al ak am an - ap| ap ao aq ar as at au av aw ax ay az bb ba ab aa ac ad ae af ag ah ai aj ak al an am - aq| aq an ap as ar au at aw av ay ax bb az ab ba ac aa ae ad ag af ai ah ak aj am ao al - ar| ar am ao at aq av as ax au az aw ba ay aa bb ad ab af ac ah ae aj ag al ai an ap ak - as| as al an au ap aw ar ay at bb av ab ax ac az ae ba ag aa ai ad ak af am ah ao aq aj - at| at ak am av ao ax aq az as ba au aa aw ad ay af bb ah ab aj ac al ae an ag ap ar ai - au| au aj al aw an ay ap bb ar ab at ac av ae ax ag az ai ba ak aa am ad ao af aq as ah - av| av ai ak ax am az ao ba aq aa as ad au af aw ah ay aj bb al ab an ac ap ae ar at ag - aw| aw ah aj ay al bb an ab ap ac ar ae at ag av ai ax ak az am ba ao aa aq ad as au af - ax| ax ag ai az ak ba am aa ao ad aq af as ah au aj aw al ay an bb ap ab ar ac at av ae - ay| ay af ah bb aj ab al ac an ae ap ag ar ai at ak av am ax ao az aq ba as aa au aw ad - az| az ae ag ba ai aa ak ad am af ao ah aq aj as al au an aw ap ay ar bb at ab av ax ac - ba| ba ac ae aa ag ad ai af ak ah am aj ao al aq an as ap au ar aw at ay av bb ax az ab - bb| bb ad af ab ah ac aj ae al ag an ai ap ak ar am at ao av aq ax as az au ba aw ay aa + ab| ab aa ae ah ac aj ak ad am af ag ar ai ap at an av al aw ao az aq as ba bb au ax ay + ac| ac ad af ai ab ag al aa an ae aj aq ah ao au am as ak ax ap ay ar av bb ba at aw az + ad| ad ac ab aa af ae aj ai ah ag al ak an am ap ao ar aq av au at as ax aw az ay bb ba + ae| ae ah aj am aa ak ar ab ap ac af av ad at az ai aw ag ba an bb al aq ay ax ao as au + af| af ai ag an ad al aq ac ao ab ae as aa au ay ah ax aj bb am ba ak ar az aw ap av at + ag| ag an al ao ai aq as af au ad ab ax ac ay ba aa bb ae az ah aw aj ak at av am ar ap + ah| ah ae aa ab aj ac af am ad ak ar ag ap ai an at al av aq az ao aw ba as au bb ay ax + ai| ai af ad ac ag ab ae an aa al aq aj ao ah am au ak as ar ay ap ax bb av at ba az aw + aj| aj am ak ap ah ar av ae at aa ac aw ab az bb ad ba af ay ai ax ag al au as an aq ao + ak| ak ap ar at am av aw aj az ah aa ba ae bb ax ab ay ac au ad as af ag ao aq ai al an + al| al ao aq au an as ax ag ay ai ad bb af ba aw ac az ab at aa av ae aj ap ar ah ak am + am| am aj ah ae ak aa ac ap ab ar av af at ad ai az ag aw al bb an ba ay aq ao ax au as + an| an ag ai af al ad ab ao ac aq as ae au aa ah ay aj ax ak ba am bb az ar ap aw at av + ao| ao al an ag aq ai ad au af as ax ab ay ac aa ba ae bb aj aw ah az at ak am av ap ar + ap| ap ak am aj ar ah aa at ae av aw ac az ab ad bb af ba ag ax ai ay au al an as ao aq + aq| aq au as ay ao ax bb al ba an ai az ag aw av af at ad ap ac ar ab ae am ak aa aj ah + ar| ar at av az ap aw ba ak bb am ah ay aj ax as ae au aa ao ab aq ac af an al ad ag ai + as| as ay ax ba au bb az aq aw ao an at al av ar ag ap ai am af ak ad ab ah aj ac ae aa + at| at ar ap ak av am ah az aj aw ba aa bb ae ab ax ac ay af as ad au ao ag ai aq an al + au| au aq ao al as an ai ay ag ax bb ad ba af ac aw ab az ae av aa at ap aj ah ar am ak + av| av az aw bb at ba ay ar ax ap am au ak as aq aj ao ah an ae al aa ac ai ag ab af ad + aw| aw bb ba ax az ay au av as at ap ao ar aq al ak an am ai aj ag ah aa ad af ae ac ab + ax| ax ba bb aw ay az at as av au ao ap aq ar ak al am an ah ag aj ai ad aa ae af ab ac + ay| ay as au aq ax ao an ba al bb az ai aw ag af av ad at ab ar ac ap am ae aa ak ah aj + az| az av at ar aw ap am bb ak ba ay ah ax aj ae as aa au ac aq ab ao an af ad al ai ag + ba| ba ax ay as bb au ao aw aq az at an av al ag ar ai ap ad ak af am ah ab ac aj aa ae + bb| bb aw az av ba at ap ax ar ay au am as ak aj aq ah ao aa al ae an ai ac ab ag ad af Another symbol set is base 10 digits, padded with leading zeros to make a common width. :: @@ -146,17 +146,17 @@ class OperationTable(SageObject): * 00 01 02 03 04 05 06 07 08 09 10 11 +------------------------------------ 00| 00 01 02 03 04 05 06 07 08 09 10 11 - 01| 01 02 00 05 03 04 07 08 06 11 09 10 - 02| 02 00 01 04 05 03 08 06 07 10 11 09 - 03| 03 06 09 00 07 10 01 04 11 02 05 08 - 04| 04 08 10 02 06 11 00 05 09 01 03 07 - 05| 05 07 11 01 08 09 02 03 10 00 04 06 - 06| 06 09 03 10 00 07 04 11 01 08 02 05 - 07| 07 11 05 09 01 08 03 10 02 06 00 04 - 08| 08 10 04 11 02 06 05 09 00 07 01 03 - 09| 09 03 06 07 10 00 11 01 04 05 08 02 - 10| 10 04 08 06 11 02 09 00 05 03 07 01 - 11| 11 05 07 08 09 01 10 02 03 04 06 00 + 01| 01 05 03 07 06 00 08 02 04 10 11 09 + 02| 02 04 06 05 10 09 00 11 07 03 01 08 + 03| 03 06 08 00 11 10 01 09 02 07 05 04 + 04| 04 09 05 11 00 02 07 06 10 01 08 03 + 05| 05 00 07 02 08 01 04 03 06 11 09 10 + 06| 06 10 00 09 01 03 02 08 11 05 04 07 + 07| 07 08 04 01 09 11 05 10 03 02 00 06 + 08| 08 11 01 10 05 07 03 04 09 00 06 02 + 09| 09 02 11 06 07 04 10 05 00 08 03 01 + 10| 10 03 09 08 02 06 11 00 01 04 07 05 + 11| 11 07 10 04 03 08 09 01 05 06 02 00 If the group's elements are not too cumbersome, or the group is small, then the string representation @@ -180,22 +180,22 @@ class OperationTable(SageObject): sage: G=QuaternionGroup() sage: T=OperationTable(G, operator.mul) sage: T.column_keys() - ((), (1,2,3,4)(5,6,7,8), ..., (1,8,3,6)(2,7,4,5)) - sage: names=['1', 'I', '-1', '-I', 'J', '-K', '-J', 'K'] + ((), (1,2,3,4)(5,6,7,8), ..., (1,7,3,5)(2,6,4,8)) + sage: names=['1', 'I', 'J', '-1', '-K', 'K', '-I', '-J'] sage: T.change_names(names=names) sage: sorted(T.translation().items()) [('-1', (1,3)(2,4)(5,7)(6,8)),..., ('K', (1,8,3,6)(2,7,4,5))] sage: T - * 1 I -1 -I J -K -J K + * 1 I J -1 -K K -I -J +------------------------ - 1| 1 I -1 -I J -K -J K - I| I -1 -I 1 K J -K -J - -1| -1 -I 1 I -J K J -K - -I| -I 1 I -1 -K -J K J - J| J -K -J K -1 -I 1 I - -K| -K -J K J I -1 -I 1 - -J| -J K J -K 1 I -1 -I - K| K J -K -J -I 1 I -1 + 1| 1 I J -1 -K K -I -J + I| I -1 K -I J -J 1 -K + J| J -K -1 -J -I I K 1 + -1| -1 -I -J 1 K -K I J + -K| -K -J I K -1 1 J -I + K| K J -I -K 1 -1 -J I + -I| -I 1 -K I -J J -1 K + -J| -J K 1 J I -I -K -1 With the right functions and a list comprehension, custom names can be easier. A multiplication table for hex digits @@ -551,7 +551,7 @@ def __getitem__(self, pair): sage: G=DiCyclicGroup(3) sage: T=OperationTable(G, operator.mul) sage: T.column_keys() - (...(1,2)(3,4)(5,6,7)...(1,3,2,4)(5,7)...) + ((), (1,3,2,4)(5,7), ..., (1,2)(3,4)(5,7,6)) sage: T[G('(1,2)(3,4)(5,6,7)'), G('(1,3,2,4)(5,7)')] (1,4,2,3)(5,6) @@ -869,11 +869,11 @@ def matrix_of_variables(self): sage: T.matrix_of_variables() [x0 x1 x2 x3 x4 x5] [x1 x0 x3 x2 x5 x4] - [x2 x4 x0 x5 x1 x3] - [x3 x5 x1 x4 x0 x2] - [x4 x2 x5 x0 x3 x1] - [x5 x3 x4 x1 x2 x0] - sage: T.column_keys()[3]*T.column_keys()[3] == T.column_keys()[4] + [x2 x5 x4 x1 x0 x3] + [x3 x4 x5 x0 x1 x2] + [x4 x3 x0 x5 x2 x1] + [x5 x2 x1 x4 x3 x0] + sage: T.column_keys()[3]*T.column_keys()[3] == T.column_keys()[0] True """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 10ef93047c7..436e8d49554 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8550,7 +8550,7 @@ def _gap_init_(self): sage: z = CyclotomicField(3).an_element(); z zeta3 sage: c = K.character([1,z,z**2]); c - Character of Subgroup of (Alternating group of order 4!/2 as a permutation group) generated by [(2,3,4)] + Character of Subgroup of (Alternating group of order 4!/2 as a permutation group) generated by [(1,2,3)] sage: c(g^2); z^2 -zeta3 - 1 -zeta3 - 1 From 3c573aef7df1659213bec2614f9ba2b788c1f4fa Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 12:53:48 +0200 Subject: [PATCH 353/665] Trac 18241: simpler import + remove SageObject inheritance --- .../geometry/polyhedron/double_description.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index 88f691dd317..1e901f41e09 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -80,9 +80,7 @@ import itertools -from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method -from sage.matrix.constructor import matrix, identity_matrix from sage.modules.free_module_element import vector from sage.rings.all import QQ @@ -115,7 +113,7 @@ def random_inequalities(d, n): return StandardAlgorithm(A) -class DoubleDescriptionPair(SageObject): +class DoubleDescriptionPair: def __init__(self, problem, A_rows, R_cols): r""" @@ -225,7 +223,7 @@ def _make_new(self, A_rows, R_cols): """ return self.__class__(self.problem, A_rows, R_cols) - def _repr_(self): + def __repr__(self): r""" Return string representation. @@ -239,12 +237,13 @@ def _repr_(self): ....: DoubleDescriptionPair, StandardAlgorithm sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) sage: DD = StandardAlgorithm(A).run() - sage: DD._repr_() + sage: DD.__repr__() 'Double description pair (A, R) defined by\n [ 1 0 1] [ 2/3 -1/3 -1/3]\nA = [ 0 1 1], R = [-1/3 2/3 -1/3]\n [-1 -1 1] [ 1/3 1/3 1/3]' """ from sage.misc.ascii_art import ascii_art + from sage.matrix.constructor import matrix s = ascii_art('Double description pair (A, R) defined by') A = ascii_art(matrix(self.A)) A._baseline = (len(self.A) / 2) @@ -426,7 +425,7 @@ def is_extremal(self, ray): sage: DD.is_extremal(DD.R[0]) True """ - A_Zray = matrix(self.problem.base_ring(), self.zero_set(ray)) + A_Zray = self._matrix(self.zero_set(ray)) return A_Zray.rank() == self.problem.dim() - 1 def are_adjacent(self, r1, r2): @@ -521,7 +520,7 @@ def first_coordinate_plane(self): return new -class Problem(SageObject): +class Problem: pair_class = DoubleDescriptionPair @@ -650,7 +649,7 @@ def dim(self): return self._A.ncols() - def _repr_(self): + def __repr__(self): """ Return a string representation. @@ -662,7 +661,7 @@ def _repr_(self): sage: A = matrix(QQ, [(1, 1), (-1, 1)]) sage: from sage.geometry.polyhedron.double_description import Problem - sage: Problem(A)._repr_() + sage: Problem(A).__repr__() 'Pointed cone with inequalities\n(1, 1)\n(-1, 1)' """ return 'Pointed cone with inequalities\n' + '\n'.join(map(str, self.A())) @@ -696,8 +695,8 @@ def initial_pair(self): pivot_rows = self.A_matrix().pivot_rows() A0 = [self.A()[pivot] for pivot in pivot_rows] Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows] - I = identity_matrix(self.base_ring(), self.dim()) - R = matrix(A0).solve_right(I) + I = self._matrix_space(self.dim(), self.dim()).identity_matrix() + R = self._matrix_space(len(A0), self.A_matrix().ncols())(A0).solve_right(I) return self.pair_class(self, A0, R.columns()), list(Ac) @@ -712,8 +711,6 @@ class StandardDoubleDescriptionPair(DoubleDescriptionPair): sage: A = matrix([(-1, 1, 0), (-1, 2, 1), (1/2, -1/2, -1)]) sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm sage: DD, _ = StandardAlgorithm(A).initial_pair() - sage: type(DD) - """ def add_inequality(self, a): From 485ae68429ba1bec374c1aa7b666f2737174189a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 13:38:48 +0200 Subject: [PATCH 354/665] Trac 5332: fix doctests and documentation --- .../rings/polynomial/polynomial_element.pyx | 5 ++--- src/sage/schemes/generic/algebraic_scheme.py | 2 +- .../schemes/projective/projective_space.py | 22 ++++++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a151ccb20f5..8bea67eded6 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -181,12 +181,11 @@ cdef class Polynomial(CommutativeAlgebraElement): EXAMPLE:: - sage: R = QQ['x']['y'] + sage: R. = QQ['y'] + sage: S. = R['x'] sage: R Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field - sage: y = R.gen() - sage: x = R.base_ring().gen() sage: f = x*y; f y*x sage: type(f) diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 08e167e4691..bfb70face23 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -194,7 +194,7 @@ def is_AlgebraicScheme(x): We create a more complicated closed subscheme:: - sage: A = AffineSpace(10, QQ) + sage: A,x = AffineSpace(10, QQ).objgens() sage: X = A.subscheme([sum(x)]); X Closed subscheme of Affine Space of dimension 10 over Rational Field defined by: x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index e93e2e90e95..1ebf2600b5a 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1,8 +1,9 @@ r""" Projective `n` space over a ring -EXAMPLES: We construct projective space over various rings of -various dimensions. +EXAMPLES: + +We construct projective space over various rings of various dimensions. The simplest projective space:: @@ -26,20 +27,25 @@ sage: X/CC Projective Space of dimension 5 over Complex Field with 53 bits of precision -The third argument specifies the printing names of the generators -of the homogenous coordinate ring. Using the special syntax with -``<`` and ``>>`` you can obtain both the space and the generators as ready to -use variables. +The third argument specifies the printing names of the generators of the +homogenous coordinate ring. Using the method `.objgens()` you can obtain both +the space and the generators as ready to use variables. :: + + sage: P2, vars = ProjectiveSpace(10, QQ, 't').objgens() + sage: vars + (t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) + +You can alternatively use the special syntax with ``<`` and ``>``. :: sage: P2. = ProjectiveSpace(2, QQ) sage: P2 Projective Space of dimension 2 over Rational Field - sage: x.parent() + sage: P2.coordinate_ring() Multivariate Polynomial Ring in x, y, z over Rational Field -The first of the three lines above is just equivalent to:: +The first of the three lines above is just equivalent to the two lines:: sage: P2 = ProjectiveSpace(2, QQ, 'xyz') sage: x,y,z = P2.gens() From f6ae58d1356c8d866423e98ae391c23f7a36a3a1 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 18 Apr 2015 14:37:49 +0200 Subject: [PATCH 355/665] Ref: start organizing the ToC of r/structure --- src/doc/en/reference/misc/index.rst | 1 + src/doc/en/reference/structure/index.rst | 98 +++++++++++++++++++----- 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 433080546ce..3ddf72b3494 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -80,6 +80,7 @@ Media .. toctree:: :maxdepth: 1 + sage/structure/graphics_file sage/media/channels sage/media/wav diff --git a/src/doc/en/reference/structure/index.rst b/src/doc/en/reference/structure/index.rst index d56c36092e6..d00892d0783 100644 --- a/src/doc/en/reference/structure/index.rst +++ b/src/doc/en/reference/structure/index.rst @@ -1,30 +1,62 @@ Basic Structures ================ +Sage Objects +------------ + .. toctree:: - :maxdepth: 2 + :maxdepth: 1 sage/structure/sage_object sage/structure/category_object + sage/structure/generators + +Parents +------- + +Parents +~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/structure/parent + sage/structure/indexed_generators + sage/structure/nonexact + sage/structure/global_options + +Old-Style Parents (Deprecated) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + sage/structure/parent_old sage/structure/parent_base sage/structure/parent_gens - sage/structure/coerce_dict - sage/structure/formal_sum - sage/structure/factorization - sage/structure/factorization_integer + sage/structure/gens_py + +Elements +-------- + +.. toctree:: + :maxdepth: 1 + sage/structure/element - sage/structure/unique_representation - sage/structure/factory - sage/structure/dynamic_class + sage/structure/element_wrapper sage/structure/list_clone sage/structure/list_clone_demo - sage/structure/mutability - sage/structure/sequence - sage/structure/element_wrapper - sage/structure/indexed_generators - sage/structure/global_options +“Mathematical” Data Structures +------------------------------ + +.. toctree:: + :maxdepth: 1 + + sage/structure/formal_sum + sage/structure/factorization + sage/structure/factorization_integer + sage/structure/sequence sage/sets/cartesian_product sage/sets/family sage/sets/set @@ -35,29 +67,53 @@ Basic Structures sage/sets/recursively_enumerated_set sage/sets/finite_set_maps sage/sets/finite_set_map_cy + sage/sets/totally_ordered_finite_set + +Sets +---- + +.. toctree:: + :maxdepth: 1 + sage/sets/integer_range sage/sets/positive_integers sage/sets/non_negative_integers sage/sets/primes - sage/sets/totally_ordered_finite_set sage/sets/real_set - sage/structure/parent +Use of Heuristic and Probabilistic Algorithms +--------------------------------------------- + +.. toctree:: + :maxdepth: 1 sage/structure/proof/proof sage/misc/proof +Utilities +--------- + +.. toctree:: + :maxdepth: 1 + + sage/structure/unique_representation + sage/structure/factory + sage/structure/dynamic_class + sage/structure/mutability + + sage/structure/coerce_dict sage/structure/coerce_exceptions + +Internals +--------- + +.. toctree:: + :maxdepth: 1 + sage/structure/debug_options - sage/structure/element_verify - sage/structure/generators - sage/structure/gens_py - sage/structure/graphics_file sage/structure/list_clone_timings sage/structure/list_clone_timings_cy sage/structure/misc - sage/structure/nonexact sage/structure/test_factory - .. include:: ../footer.txt From d0ec65bb221ff76dd0c63b606659ccfd3e4015e6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 14:45:38 +0200 Subject: [PATCH 356/665] Trac 18239: last doctest failure --- src/sage/categories/examples/hopf_algebras_with_basis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/examples/hopf_algebras_with_basis.py b/src/sage/categories/examples/hopf_algebras_with_basis.py index e506b8b46a5..1808884d00d 100644 --- a/src/sage/categories/examples/hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/hopf_algebras_with_basis.py @@ -90,7 +90,7 @@ def algebra_generators(self): sage: A = HopfAlgebrasWithBasis(QQ).example(); A An example of Hopf algebra with basis: the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field sage: A.algebra_generators() - Finite family {(1,2,3): B[(1,2,3)], (1,3): B[(1,3)]} + Finite family {(1,3): B[(1,3)], (1,2,3): B[(1,2,3)]} """ return Family(self._group.gens(), self.monomial) From 2d5eea9285b4447a9ecfe346acfdd6f7f82a0982 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sat, 18 Apr 2015 14:51:32 +0200 Subject: [PATCH 357/665] Correct the treatment of the option figsize for jmol --- src/sage/plot/plot3d/base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index fd670b5ad38..fac63552fa8 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -251,7 +251,7 @@ cdef class Graphics3d(SageObject): script = '''set defaultdirectory "%s"\nscript SCRIPT\n''' % scene_zip jdata.export_image(targetfile=preview_png, datafile=script, image_type="PNG", - figsize=opts['figsize']) + figsize=opts['figsize'][0]) from sage.repl.rich_output.output_graphics3d import OutputSceneJmol from sage.repl.rich_output.buffer import OutputBuffer scene_zip = OutputBuffer.from_file(scene_zip) From b340eebb3cec1d5f273b9c382599f23736045e98 Mon Sep 17 00:00:00 2001 From: Simon King Date: Sat, 18 Apr 2015 15:49:50 +0200 Subject: [PATCH 358/665] Use embedded signature for introspection --- src/sage/misc/nested_class.pyx | 19 ++++++++- src/sage/misc/sageinspect.py | 78 +++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index ad45c09f09f..e05930d55d6 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -311,7 +311,24 @@ class MainClass(object): sage: MainClass.NestedClass.NestedSubClass.__name__ 'MainClass.NestedClass.NestedSubClass' """ - pass + def dummy(self, x, *args, r=(1,2,3.4), **kwds): + """ + A dummy method to demonstrate the embedding of + method signature for nested classes. + + TESTS:: + + sage: from sage.misc.nested_class import MainClass + sage: print MainClass.NestedClass.NestedSubClass.dummy.__doc__ + NestedSubClass.dummy(self, x, *args, r=(1, 2, 3.4), **kwds) + File: sage/misc/nested_class.pyx (starting at line 314) + + A dummy method to demonstrate the embedding of + method signature for nested classes. + ... + + """ + pass class SubClass(MainClass): r""" diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index aa3c6a07acc..bb405d655c3 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -212,6 +212,43 @@ def _extract_embedded_position(docstring): original = res.group('ORIGINAL') return (original, filename, lineno) +def _extract_embedded_signature(docstring, name): + r""" + If docstring starts with the embedded of a method called ``name``, return + a tuple (original_docstring, argspec). If not, return (docstring, None). + + See :trac:`17814`. + + INPUT: ``docstring`` (string) + + AUTHORS: + + - Simon King + + EXAMPLES:: + + sage: from sage.misc.sageinspect import _extract_embedded_signature + sage: from sage.misc.nested_class import MainClass + sage: print _extract_embedded_signature(MainClass.NestedClass.NestedSubClass.dummy.__doc__, 'dummy')[0] + File: sage/misc/nested_class.pyx (starting at line 314) + ... + sage: _extract_embedded_signature(MainClass.NestedClass.NestedSubClass.dummy.__doc__, 'dummy')[1] + ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + + """ + # If there is an embedded signature, it is in the first line + L = docstring.split(os.linesep, 1) + firstline = L[0] + # It is possible that the signature is of the form ClassName.method_name, + # and thus we need to do the following: + if name not in firstline: + return docstring, None + signature = firstline.split(name, 1)[-1] + if signature.startswith("(") and signature.endswith(")"): + docstring = L[1] if len(L)>1 else '' # Remove first line, keep the rest + def_string = "def "+name+signature+": pass" + return docstring, inspect.ArgSpec(*_sage_getargspec_cython(def_string)) + return docstring, None class BlockFinder: """ @@ -1325,6 +1362,13 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: sage_getargspec(gap) ArgSpec(args=['self', 'x', 'name'], varargs=None, keywords=None, defaults=(None,)) + By :trac:`17814`, the following gives the correct answer (previously, the + defaults would have been found ``None``):: + + sage: from sage.misc.nested_class import MainClass + sage: sage_getargspec(MainClass.NestedClass.NestedSubClass.dummy) + ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + AUTHORS: @@ -1335,6 +1379,8 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return """ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import AbstractMethod + if inspect.isclass(obj): + return sage_getargspec(obj.__call__) if isinstance(obj, (lazy_attribute, AbstractMethod)): source = sage_getsource(obj) return inspect.ArgSpec(*_sage_getargspec_cython(source)) @@ -1344,7 +1390,14 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return return inspect.ArgSpec(*obj._sage_argspec_()) except (AttributeError, TypeError): pass + # If we are lucky, the function signature is embedded in the docstring. + docstring = _sage_getdoc_unformatted(obj) + name = obj.__name__ if hasattr(obj,'__name__') else type(obj).__name__ + argspec = _extract_embedded_signature(docstring, name)[1] + if argspec is not None: + return argspec if hasattr(obj, 'func_code'): + # Note that this may give a wrong result for the constants! try: args, varargs, varkw = inspect.getargs(obj.func_code) return inspect.ArgSpec(args, varargs, varkw, obj.func_defaults) @@ -1364,15 +1417,16 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return base_spec = sage_getargspec(obj.func) return base_spec return sage_getargspec(obj.__class__.__call__) - elif inspect.isclass(obj): - return sage_getargspec(obj.__call__) elif (hasattr(obj, '__objclass__') and hasattr(obj, '__name__') and obj.__name__ == 'next'): # Handle sage.rings.ring.FiniteFieldIterator.next and similar # slot wrappers. This is mainly to suppress Sphinx warnings. return ['self'], None, None, None else: - # Perhaps it is binary and defined in a Cython file + # We try to get the argspec by reading the source, which may be + # expensive, but should only be needed for functions defined outside + # of the Sage library (since otherwise the signature should be + # embedded in the docstring) source = sage_getsource(obj) if source: return inspect.ArgSpec(*_sage_getargspec_cython(source)) @@ -1388,7 +1442,6 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return except TypeError: # arg is not a code object # The above "hopefully" was wishful thinking: return inspect.ArgSpec(*_sage_getargspec_cython(sage_getsource(obj))) - #return _sage_getargspec_from_ast(sage_getsource(obj)) try: defaults = func_obj.__defaults__ except AttributeError: @@ -1590,23 +1643,10 @@ def sage_getdoc_original(obj): else: typ = type(obj) - s = _sage_getdoc_unformatted(obj) + s,argspec = _extract_embedded_signature(_sage_getdoc_unformatted(obj), typ.__name__) if s: pos = _extract_embedded_position(s) - if pos is None: - # It can still be that the doc starts with the signature of the - # class' __init__ method, but does not contain embedding - # information. This is particularly critical if it contains * or - # **, which would be misinterpreted by sphinx. - name = typ.__name__.split('.')[-1] - if s.startswith(name + "("): - L = s.split(os.linesep, 1) - if L[0].endswith(")"): - if len(L) < 2: - s = "" # The doc was just one line with the signature - else: - s = L[1] # Remove first line, keep the rest - else: + if pos is not None: s = pos[0] if not s: try: From 770ad60c6812e524b6d957b2179bd486e2d3896e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 16:41:47 +0200 Subject: [PATCH 359/665] Trac 18241: move code in double_description.py --- .../geometry/polyhedron/double_description.py | 135 ++++++++---------- 1 file changed, 57 insertions(+), 78 deletions(-) diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index 1e901f41e09..ec8b687ccfa 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -81,9 +81,9 @@ import itertools from sage.misc.cachefunc import cached_method -from sage.modules.free_module_element import vector from sage.rings.all import QQ - +from sage.modules.free_module_element import vector +from sage.matrix.matrix_space import MatrixSpace def random_inequalities(d, n): """ @@ -156,37 +156,8 @@ def __init__(self, problem, A_rows, R_cols): self.one = problem._field.one() self.zero = problem._field.zero() - # a cache for scalar product - self.cache = {} - - def _matrix(self, data): - r""" - Create a new matrix using the cached matrix spaces in ``self.problem``. - - INPUT: - - - ``data`` -- a list of lists - - EXAMPLES:: - - sage: from sage.geometry.polyhedron.double_description import \ - ....: DoubleDescriptionPair, Problem - sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) - sage: alg = Problem(A) - sage: DD = DoubleDescriptionPair(alg, - ....: [(1, 0, 1), (0, 1, 1), (-1, -1, 1)], - ....: [(2/3, -1/3, 1/3), (-1/3, 2/3, 1/3), (-1/3, -1/3, 1/3)]) - sage: DD._matrix([[1,2],[3,4]]) - [1 2] - [3 4] - sage: parent(_) - Full MatrixSpace of 2 by 2 dense matrices over Rational Field - """ - if data: - M = self.problem._matrix_space(len(data), len(data[0])) - return M(data) - else: - return self.problem._matrix_space(0,0)() + # a cache for scalar products (see the method zero_set) + self.zero_set_cache = {} def _make_new(self, A_rows, R_cols): r""" @@ -277,7 +248,8 @@ def inner_product_matrix(self): [0 1 0] [0 0 1] """ - return self._matrix([[a.inner_product(r) for r in self.R] for a in self.A]) + from sage.matrix.constructor import matrix + return matrix(self.problem.base_ring(), [[a.inner_product(r) for r in self.R] for a in self.A]) def cone(self): """ @@ -384,16 +356,13 @@ def zero_set(self, ray): """ Return the zero set (active set) `Z(r)`. - This method is cached, but the cache is reset to zero in case - :meth:`add_inequality` is called. - INPUT: - ``ray`` -- a ray vector. OUTPUT: - A tuple containing the inequality vectors that are zero on ``ray``. + A set containing the inequality vectors that are zero on ``ray``. EXAMPLES:: @@ -403,14 +372,14 @@ def zero_set(self, ray): sage: r = DD.R[0]; r (2/3, -1/3, 1/3) sage: DD.zero_set(r) - [(0, 1, 1), (-1, -1, 1)] + {(-1, -1, 1), (0, 1, 1)} """ - if ray not in self.cache: - self.cache[ray] = (0, []) - n, t = self.cache[ray] + if ray not in self.zero_set_cache: + self.zero_set_cache[ray] = (0, set()) + n, t = self.zero_set_cache[ray] if n != len(self.A): - t.extend(self.A[i] for i in range(n,len(self.A)) if self.A[i].inner_product(ray) == self.zero) - self.cache[ray] = (len(self.A), t) + t.update(self.A[i] for i in range(n,len(self.A)) if self.A[i].inner_product(ray) == self.zero) + self.zero_set_cache[ray] = (len(self.A), t) return t def is_extremal(self, ray): @@ -425,9 +394,38 @@ def is_extremal(self, ray): sage: DD.is_extremal(DD.R[0]) True """ - A_Zray = self._matrix(self.zero_set(ray)) + from sage.matrix.constructor import matrix + A_Zray = matrix(self.problem.base_ring(), list(self.zero_set(ray))) return A_Zray.rank() == self.problem.dim() - 1 + @cached_method + def matrix_space(self, nrows, ncols): + r""" + Return a matrix space of size ``nrows`` and ``ncols`` over the base ring + of ``self``. + + These matrix spaces are cached to avoid the their creation in the very + demanding :meth:`add_inequality` and more precisely :meth:`are_adjacent`. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.double_description import Problem + sage: A = matrix(QQ, [(1,0,1), (0,1,1), (-1,-1,1)]) + sage: DD, _ = Problem(A).initial_pair() + sage: DD.matrix_space(2,2) + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: DD.matrix_space(3,2) + Full MatrixSpace of 3 by 2 dense matrices over Rational Field + + sage: K. = QuadraticField(2) + sage: A = matrix([[1,sqrt2],[2,0]]) + sage: DD, _ = Problem(A).initial_pair() + sage: DD.matrix_space(1,2) + Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 + with defining polynomial x^2 - 2 + """ + return MatrixSpace(self.problem.base_ring(), nrows, ncols) + def are_adjacent(self, r1, r2): """ Return whether the two rays are adjacent. @@ -452,10 +450,14 @@ def are_adjacent(self, r1, r2): sage: DD.are_adjacent(DD.R[0], DD.R[3]) False """ - Z_r1 = self.zero_set(r1) - Z_r2 = self.zero_set(r2) - Z_12 = set(Z_r1).intersection(Z_r2) - A_Z12 = self._matrix(list(Z_12)) + Z = self.zero_set(r1).intersection(self.zero_set(r2)) + if not Z: + return self.problem.dim() == 2 + Z = list(Z) + + # here we try to create a matrix as fast as possible + # since the generic matrix constructor is very slow (trac #18231) + A_Z12 = self.matrix_space(len(Z), len(Z[0])).matrix(Z, coerce=False) return A_Z12.rank() == self.problem.dim() - 2 def dual(self): @@ -546,35 +548,12 @@ def __init__(self, A): (-1, 1) """ assert A.rank() == A.ncols() # implementation assumes maximal rank + if A.is_mutable(): + A = A.__copy__() + A.set_immutable() self._A = A self._field = A.base_ring().fraction_field() - @cached_method - def _matrix_space(self, nrows, ncols): - r""" - Cache of matrix spaces to avoid their creation in the very demanding - :meth:`StandardDoubleDescriptionPair.add_inequality`. - - EXAMPLES:: - - sage: A = matrix([(1, 1), (-1, 1)]) - sage: from sage.geometry.polyhedron.double_description import Problem - sage: P = Problem(A) - sage: P._matrix_space(2,2) - Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: P._matrix_space(3,2) - Full MatrixSpace of 3 by 2 dense matrices over Rational Field - - sage: K. = QuadraticField(2) - sage: A = matrix([[1,sqrt2],[2,0]]) - sage: P = Problem(A) - sage: P._matrix_space(1,2) - Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 - with defining polynomial x^2 - 2 - """ - from sage.matrix.matrix_space import MatrixSpace - return MatrixSpace(self.base_ring(), nrows, ncols) - @cached_method def A(self): """ @@ -646,7 +625,6 @@ def dim(self): sage: Problem(A).dim() 2 """ - return self._A.ncols() def __repr__(self): @@ -695,8 +673,9 @@ def initial_pair(self): pivot_rows = self.A_matrix().pivot_rows() A0 = [self.A()[pivot] for pivot in pivot_rows] Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows] - I = self._matrix_space(self.dim(), self.dim()).identity_matrix() - R = self._matrix_space(len(A0), self.A_matrix().ncols())(A0).solve_right(I) + from sage.matrix.constructor import identity_matrix, matrix + I = identity_matrix(self.base_ring(), self.dim()) + R = matrix(self.base_ring(), A0).solve_right(I) return self.pair_class(self, A0, R.columns()), list(Ac) From bee81efd147539fce1f0ef7f1e0351766dfe27a2 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 17:02:07 +0200 Subject: [PATCH 360/665] Trac 18215: fix a failing doctest --- .../hecke_triangle_groups.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 6b7f15920d7..732f7fea7ba 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -933,24 +933,25 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): [((4, 1), (3, 1)), ((2, 2),), ((3, 2),), ((3, 1), (1, 1)), ((4, 1), (1, 1)), ((4, 1), (2, 1)), ((3, 1), (2, 1)), ((2, 1), (1, 1))] sage: [key for key in G._conj_prim] - [0, 15*lam + 6, 33*lam + 21, 9*lam + 5, 7*lam + 6, lam - 3, -4, 4*lam] + [0, lam - 3, 15*lam + 6, 7*lam + 6, 4*lam, 9*lam + 5, 33*lam + 21, -4] sage: for key in G._conj_prim: print G._conj_prim[key] [[V(4)]] + [[U], [U]] [[V(1)*V(3)], [V(2)*V(4)]] - [[V(2)*V(3)]] - [[V(3)*V(4)], [V(1)*V(2)]] [[V(1)*V(4)]] - [[U], [U]] - [[S], [S]] [[V(3)], [V(2)]] + [[V(3)*V(4)], [V(1)*V(2)]] + [[V(2)*V(3)]] + [[S], [S]] sage: [key for key in G._conj_nonprim] - [32*lam + 16, lam - 3, -lam - 2] + [lam - 3, 32*lam + 16, -lam - 2] sage: for key in G._conj_nonprim: print G._conj_nonprim[key] - [[V(2)^2], [V(3)^2]] [[U^(-1)], [U^(-1)]] + [[V(2)^2], [V(3)^2]] [[U^(-2)], [U^2], [U^(-2)], [U^2]] + sage: G.element_repr_method("default") """ From 1f4b5b6d6f867aa86aeec37e8bd485f67a83d81b Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sat, 18 Apr 2015 08:04:22 -0700 Subject: [PATCH 361/665] bugfix --- src/sage/combinat/root_system/integrable_representations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index b03df437213..687930a2836 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -643,7 +643,7 @@ def next_level(wt): candidates = [x + (k - x.level())*Lambda[0] for x in list(R)] ret = [] for x in candidates: - if self._from_weight_helper(x, check=True): + if self._from_weight_helper(self._Lam-x, check=True): t = 0 while self.m(self.from_weight(x-t*self._delta)) == 0: t += 1 From fc99d79618104040305c112bd90d71c0669b0940 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sat, 18 Apr 2015 08:24:31 -0700 Subject: [PATCH 362/665] replaced dominant_maximal method --- .../root_system/integrable_representations.py | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 687930a2836..c5220907d53 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -78,15 +78,15 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).strings() - 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 2*Lambda[0] + Lambda[2]: 4 31 161 665 2380 7658 22721 63120 166085 417295 1007601 2349655 - Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 - Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 + Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 + 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(Lambda[0]+Lambda[1]).strings() # long time - Lambda[3] + Lambda[4] - delta: 3 25 136 590 2205 7391 22780 65613 178660 463842 1155717 2777795 Lambda[0] + Lambda[1]: 1 10 62 293 1165 4097 13120 38997 109036 289575 735870 1799620 + Lambda[3] + Lambda[4] - delta: 3 25 136 590 2205 7391 22780 65613 178660 463842 1155717 2777795 In this example, we construct the extended weight lattice of Cartan type `A_3^{(1)}`, then define ``Lambda`` to be the fundamental @@ -129,18 +129,18 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 Lambda[0] sage: IntegrableRepresentation(4*L0).strings(depth=20) - 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 - 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 + 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 + 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 An example in type `C_2^{(1)}`:: sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]) sage: v.strings() # long time - 2*Lambda[1] - delta: 1 4 15 44 122 304 721 1612 3469 7176 14414 28124 - Lambda[0] + Lambda[2] - delta: 1 5 18 55 149 372 872 1941 4141 8523 17005 33019 2*Lambda[0]: 1 2 9 26 77 194 477 1084 2387 5010 10227 20198 + Lambda[0] + Lambda[2] - delta: 1 5 18 55 149 372 872 1941 4141 8523 17005 33019 + 2*Lambda[1] - delta: 1 4 15 44 122 304 721 1612 3469 7176 14414 28124 2*Lambda[2] - 2*delta: 2 7 26 72 194 467 1084 2367 5010 10191 20198 38907 """ def __init__(self, Lam): @@ -625,7 +625,7 @@ def m(self, n): print "m: error - failed to compute m%s"%n.__repr__() return ret - def dommax(self): + def dominant_maximal(self): """ A weight `\\mu` is *maximal* if it has nonzero multiplicity but `\\mu+\\delta`` has multiplicity zero. There are a finite number @@ -650,24 +650,6 @@ def next_level(wt): ret.append(x-t*self._delta) return ret - # FIXME: Make this generate itself without having needing to be called by string() - #@lazy_attribute - def dominant_maximal(self): - """ - Find the finite set of dominant maximal weights. - """ - ret = set() - delta = self._Q.null_root() - for x in self._ddict.values(): - if self.m(x) > 0: - if min(x) == 0: - ret.add(x) - else: - y = self.from_weight(self.to_weight(x) + delta) - if self.m(y) == 0: - ret.add(x) - return [self.to_weight(x) for x in ret] - def string(self, max_weight, depth=12): """ Return the list of multiplicities `m(\Lambda - k \delta)` where @@ -702,8 +684,8 @@ def strings(self, depth=12): sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(2*Lambda[0]).strings(depth=25) - 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 + 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ # FIXME: This call to string should not be necessary as it is From 2fba20c9f1f07e3707b42b8b8aeeae341bd7cd0d Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 18 Apr 2015 18:23:37 +0200 Subject: [PATCH 363/665] Trac 18241: avoid a repetition in the doc --- src/sage/geometry/polyhedron/double_description.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index ec8b687ccfa..bb608143100 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -694,8 +694,7 @@ class StandardDoubleDescriptionPair(DoubleDescriptionPair): def add_inequality(self, a): """ - Add an inequality to the double description with the inequality ``a`` - added. + Add the inequality ``a`` to the matrix `A` of the double description. INPUT: From d4866c649032b7396ab6adab9690c72ba230d7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 18 Apr 2015 22:17:43 +0200 Subject: [PATCH 364/665] trac #11529 making it work without ranker --- src/sage/combinat/rooted_tree.py | 52 +++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 646e68b13e8..fa097df4975 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -7,7 +7,6 @@ """ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets -from sage.combinat.ranker import on_fly from sage.combinat.abstract_tree import (AbstractClonableTree, AbstractLabelledClonableTree) from sage.misc.cachefunc import cached_function @@ -21,6 +20,7 @@ from sage.structure.list_clone import NormalizedClonableList from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation +from sage.misc.cachefunc import cached_method @cached_function @@ -175,7 +175,20 @@ def __init__(self, parent=None, children=[], check=True): children = [self.__class__(parent, x) for x in children] NormalizedClonableList.__init__(self, parent, children, check=check) - _unordered_ranker = on_fly() + def sort_key(self): + """ + Return a list of numbers + + The tree ``self`` must be normalized before calling this ! + """ + l = len(self) + if l == 0: + return (0,) + resu = [l] + [u for t in self for u in t.sort_key()] + return tuple(resu) + + def __hash__(self): + return hash(self.sort_key()) def normalize(self): r""" @@ -206,20 +219,16 @@ def normalize(self): sage: rt2 = RT([[[]],[]]) sage: rt1 is rt2 False - sage: rt1._get_list() is rt2._get_list() + sage: rt1._get_list() == rt2._get_list() True """ - rank, unrank = self._unordered_ranker self._require_mutable() for st in self: assert st.is_immutable(), "Subtree {} is not normalized".format(st) - self._get_list().sort(key=rank) + self._get_list().sort(key=lambda t: t.sort_key()) # ensure unique representation self.set_immutable() - res = unrank(rank(self)) - if self is not res: - self._set_list(res._get_list()) def is_empty(self): r""" @@ -679,11 +688,11 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): Children are reordered in a session dependent order:: - sage: y = LabelledRootedTree([], label = 5); x - 3[] - sage: xyy2 = LabelledRootedTree((x, y, y), label = 2); xyy2 #random + sage: y = LabelledRootedTree([], label = 5); y + 5[] + sage: xyy2 = LabelledRootedTree((x, y, y), label = 2); xyy2 2[3[], 5[], 5[]] - sage: yxy2 = LabelledRootedTree((y, x, y), label = 2); yxy2 #random + sage: yxy2 = LabelledRootedTree((y, x, y), label = 2); yxy2 2[3[], 5[], 5[]] sage: xyy2 == yxy2 True @@ -699,7 +708,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): TESTS:: - sage: xyy2._get_list() is yxy2._get_list() + sage: xyy2._get_list() == yxy2._get_list() True """ __metaclass__ = ClasscallMetaclass @@ -739,6 +748,21 @@ def _auto_parent(cls): """ return LabelledRootedTrees() + def sort_key(self): + """ + Return a list of numbers and labels + + The tree ``self`` must be normalized before calling this ! + """ + l = len(self) + if l == 0: + return ((0, self.label()),) + resu = [(l, self.label())] + [u for t in self for u in t.sort_key()] + return tuple(resu) + + def __hash__(self): + return hash(self.sort_key()) + _UnLabelled = RootedTree @@ -811,7 +835,7 @@ def _an_element_(self): EXAMPLE:: sage: LabelledRootedTrees().an_element() # indirect doctest - alpha[3[], 42[3[], 3[]], 5[None[]]] + alpha[3[], 5[None[]], 42[3[], 3[]]] """ LT = self._element_constructor_ t = LT([], label=3) From 0e8ef000e434b654c76299b2ea694ca15be965a3 Mon Sep 17 00:00:00 2001 From: Simon King Date: Sat, 18 Apr 2015 23:44:46 +0200 Subject: [PATCH 365/665] Catch syntax error when extraction of signature fails --- src/sage/misc/sageinspect.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index bb405d655c3..c8405f42ad7 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -234,6 +234,8 @@ def _extract_embedded_signature(docstring, name): ... sage: _extract_embedded_signature(MainClass.NestedClass.NestedSubClass.dummy.__doc__, 'dummy')[1] ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') + ('x.__call__(...) <==> x(...)', None) """ # If there is an embedded signature, it is in the first line @@ -247,7 +249,10 @@ def _extract_embedded_signature(docstring, name): if signature.startswith("(") and signature.endswith(")"): docstring = L[1] if len(L)>1 else '' # Remove first line, keep the rest def_string = "def "+name+signature+": pass" - return docstring, inspect.ArgSpec(*_sage_getargspec_cython(def_string)) + try: + return docstring, inspect.ArgSpec(*_sage_getargspec_cython(def_string)) + except SyntaxError: + docstring = os.linesep.join(L) return docstring, None class BlockFinder: From dffa7659dc2f0129458fa7394b851fa018f91363 Mon Sep 17 00:00:00 2001 From: Simon King Date: Sun, 19 Apr 2015 00:47:04 +0200 Subject: [PATCH 366/665] Introspection of builtins returns generic data instead of raising an error --- src/sage/misc/sageinspect.py | 46 +++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index c8405f42ad7..40e39b97d8f 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -93,13 +93,14 @@ sage: sage_getsource(sage.misc.sageinspect.sage_getfile)[4:] 'sage_getfile(obj):...' -Unfortunately, there is no argspec extractable from builtins:: +Unfortunately, no argspec is extractable from builtins. Hence, we use a +generic argspec:: sage: sage_getdef(''.find, 'find') - 'find( [noargspec] )' + 'find(*args, **kwds)' sage: sage_getdef(str.find, 'find') - 'find( [noargspec] )' + 'find(*args, **kwds)' By :trac:`9976` and :trac:`14017`, introspection also works for interactively defined Cython code, and with rather tricky argument lines:: @@ -1196,6 +1197,12 @@ def sage_getfile(obj): sage: sage_getfile(Foo) '...pyx' + By :trac:`18249`, we return an empty string for Python builtins. In that + way, there is no error when the user types, for example, ``range?``:: + + sage: sage_getfile(range) + '' + AUTHORS: - Nick Alexander @@ -1216,7 +1223,10 @@ def sage_getfile(obj): return sage_getfile(obj.__class__) #inspect.getabsfile(obj.__class__) # No go? fall back to inspect. - sourcefile = inspect.getabsfile(obj) + try: + sourcefile = inspect.getabsfile(obj) + except TypeError: # this happens for Python builtins + return '' if sourcefile.endswith(os.path.extsep+'so'): return sourcefile[:-3]+os.path.extsep+'pyx' return sourcefile @@ -1374,6 +1384,17 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: sage_getargspec(MainClass.NestedClass.NestedSubClass.dummy) ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) + In :trac:`18249` was decided to return a generic signature for Python + builtin functions, rather than to raise an error (which is what Python's + inspect module does):: + + sage: import inspect + sage: inspect.getargspec(range) + Traceback (most recent call last): + ... + TypeError: is not a Python function + sage: sage_getargspec(range) + ArgSpec(args=[], varargs='args', keywords='kwds', defaults=None) AUTHORS: @@ -1432,7 +1453,10 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return # expensive, but should only be needed for functions defined outside # of the Sage library (since otherwise the signature should be # embedded in the docstring) - source = sage_getsource(obj) + try: + source = sage_getsource(obj) + except TypeError: # happens for Python builtins + source = '' if source: return inspect.ArgSpec(*_sage_getargspec_cython(source)) else: @@ -1445,12 +1469,18 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return try: args, varargs, varkw = inspect.getargs(func_obj) except TypeError: # arg is not a code object - # The above "hopefully" was wishful thinking: - return inspect.ArgSpec(*_sage_getargspec_cython(sage_getsource(obj))) + # The above "hopefully" was wishful thinking: + try: + return inspect.ArgSpec(*_sage_getargspec_cython(sage_getsource(obj))) + except TypeError: # This happens for Python builtins + # The best we can do is to return a generic argspec + args = [] + varargs = 'args' + varkw = 'kwds' try: defaults = func_obj.__defaults__ except AttributeError: - defaults = tuple([]) + defaults = None return inspect.ArgSpec(args, varargs, varkw, defaults) def sage_getdef(obj, obj_name=''): From ea55f2a0b4a31e6cd8cd92163009f25a90eeca1c Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 18 Apr 2015 19:16:11 +0200 Subject: [PATCH 367/665] #5332 fix errors in the last two commits --- src/sage/modular/dirichlet.py | 2 +- .../rings/polynomial/multi_polynomial_element.py | 4 ++-- src/sage/rings/polynomial/polynomial_element.pyx | 4 ++-- src/sage/schemes/elliptic_curves/padics.py | 12 ++++++------ .../hyperelliptic_curves/monsky_washnitzer.py | 3 +-- src/sage/schemes/plane_curves/affine_curve.py | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 5416867eda5..f13660fdf7f 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -212,7 +212,7 @@ def __init__(self, parent, x, check=True): :: - sage: G. = DirichletGroup(35) + sage: G, x = DirichletGroup(35).objgens() sage: e = x[0]*x[1]; e Dirichlet character modulo 35 of conductor 35 mapping 22 |--> zeta12^3, 31 |--> zeta12^2 sage: e.order() diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 5c88ba26b88..11239961c9f 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -344,8 +344,8 @@ def __init__(self, parent, x): """ EXAMPLES:: - sage: R = PolynomialRing(QQbar, 10, 'x') - sage: R.gens() + sage: R, x = PolynomialRing(QQbar, 10, 'x').objgens() + sage: x (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) sage: loads(dumps(x)) == x True diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 8bea67eded6..2e3c846c0af 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -183,8 +183,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R. = QQ['y'] sage: S. = R['x'] - sage: R - Univariate Polynomial Ring in y over Univariate Polynomial Ring in x + sage: S + Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field sage: f = x*y; f y*x diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index d552da37d76..97886593a7b 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -447,12 +447,12 @@ def _multiply_point(E, R, P, m): ....: naive = R(Q[0].numerator()), \ ....: R(Q[1].numerator()), \ ....: R(Q[0].denominator().sqrt()) - ....: triple = _multiply_point(E, R, P, n) - ....: assert (triple[0] == naive[0]) and ( \ - ....: (triple[1] == naive[1] and triple[2] == naive[2]) or \ - ....: (triple[1] == -naive[1] and triple[2] == -naive[2])), \ - ....: "_multiply_point() gave an incorrect answer" - ....: Q = Q + P + ....: triple = _multiply_point(E, R, P, n) + ....: assert (triple[0] == naive[0]) and ( \ + ....: (triple[1] == naive[1] and triple[2] == naive[2]) or \ + ....: (triple[1] == -naive[1] and triple[2] == -naive[2])), \ + ....: "_multiply_point() gave an incorrect answer" + ....: Q = Q + P """ assert m >= 1 diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 3dbcfaf3bf1..a58661b9511 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -293,8 +293,7 @@ def create_element(self, p0, p1, p2, check=True): sage: B. = PolynomialRing(Integers(125)) sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4)) - sage: A = R.poly_ring() - sage: z = R.gen() + sage: A, z = R.poly_ring().objgen() sage: R.create_element(z^2, z+1, 3) (T^2) + (T + 1)*x + (3)*x^2 """ diff --git a/src/sage/schemes/plane_curves/affine_curve.py b/src/sage/schemes/plane_curves/affine_curve.py index d558c73d73d..d080ac7db89 100644 --- a/src/sage/schemes/plane_curves/affine_curve.py +++ b/src/sage/schemes/plane_curves/affine_curve.py @@ -240,7 +240,7 @@ def rational_points(self, algorithm="enum"): sage: A. = AffineSpace(2,GF(9,'a')) sage: C = Curve(x^2 + y^2 - 1) sage: C - Affine Curve over Finite Field in a of size 3^2 defined by x0^2 + x1^2 - 1 + Affine Curve over Finite Field in a of size 3^2 defined by x^2 + y^2 - 1 sage: C.rational_points() [(0, 1), (0, 2), (1, 0), (2, 0), (a + 1, a + 1), (a + 1, 2*a + 2), (2*a + 2, a + 1), (2*a + 2, 2*a + 2)] """ From bd4ee7dd6447a23fbf7f8e68030aac8fa173b532 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Sun, 19 Apr 2015 10:30:01 +0200 Subject: [PATCH 368/665] 16659: documentation lift idempotent --- .../finite_dimensional_algebras_with_basis.py | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index bffbd52fbef..648d8ee2d98 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -435,7 +435,7 @@ def central_orthogonal_idempotents(self): sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field + and b:x->y) over Rational Field sage: A.central_orthogonal_idempotents() [y, x] sage: Z12 = Monoids().Finite().example(); Z12 @@ -457,8 +457,17 @@ def central_orthogonal_idempotents(self): def _lift_idempotent(self, x): r""" - Lift an idempotent of the semisimple quotient of ``self`` into an - idempotent of ``self``. + Lift a central orthogonal idempotent of the semisimple quotient of + ``self`` into a central orthogonal idempotent of ``self``. + + ALGORITHM: + + Let '\overline{e}' be a central orthogonal idempotent of the + semisimple quotient `\overline{A}` of a finite dimensional algebra + `A`. Let `e \in A` such that the projection of `e` in + `\overline{A}` is `\overline{e}`. We iterate the formula + `1 - (1 - e^2)^2` until having an idempotent. See [CR62] for + correctness and termination proofs. EXAMPLES:: @@ -467,9 +476,19 @@ def _lift_idempotent(self, x): sage: orth = Aquo.central_orthogonal_idempotents() sage: A._lift_idempotent(orth[1]) x + + REFERENCES: + + .. [CR62] Curtis, Charles W.; Reiner, Irving + "Representation theory of finite groups and associative + algebras." + Pure and Applied Mathematics, Vol. XI Interscience Publishers, a + division of John Wiley & Sons, New York-London 1962 + pp 545--556 """ idempOld = None assert x in self.semisimple_quotient() + assert (x == x*x), "Element is not an idempotent" idemp = x.lift() p = idemp.parent() while idemp != idempOld: @@ -563,8 +582,7 @@ def pierce_decomposition_component(self, ei, ej): Free module generated by {} over Rational Field - We can for example recover the unique 2 dimensional representation - of S4:: + We recover the unique 2 dimensional representations of S4:: sage: A4 = SymmetricGroup(4).algebra(QQ) sage: e = A4.central_orthogonal_idempotents()[2] From 4c9cc1188aaafc8fb0ac56387184fd109926f1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 19 Apr 2015 10:39:43 +0200 Subject: [PATCH 369/665] trac #11529 fixing doc for rooted trees --- src/sage/combinat/rooted_tree.py | 78 +++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index fa097df4975..c5760f195d1 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -20,7 +20,6 @@ from sage.structure.list_clone import NormalizedClonableList from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method @cached_function @@ -177,9 +176,23 @@ def __init__(self, parent=None, children=[], check=True): def sort_key(self): """ - Return a list of numbers + Return a tuple of numbers that can be used to sort the rooted trees. - The tree ``self`` must be normalized before calling this ! + This tuple is in fact an encoding of the tree. The values are + the valences of the vertices. The first value is the valence of the + root. Then the rest of the tuple is the concatenation of the tuples + associated to subtrees. + + The tree ``self`` must be normalized before calling this, meaning + that it subtrees have to be sorted according to their sort key. + + EXAMPLES:: + + sage: RT = RootedTree + sage: RT([[],[[]]]).sort_key() + (2, 0, 1, 0) + sage: RT([[[]],[]]).sort_key() + (2, 0, 1, 0) """ l = len(self) if l == 0: @@ -188,6 +201,17 @@ def sort_key(self): return tuple(resu) def __hash__(self): + """ + Return a hash for ``self``. + + This is based on :meth:`sort_key`. + + EXAMPLES:: + + sage: RT = RootedTree + sage: hash(RT([[],[[]]])) # indirect doctest + 2578595415271398032 + """ return hash(self.sort_key()) def normalize(self): @@ -206,9 +230,7 @@ def normalize(self): The normalization has a recursive definition. It means first that every sub-tree is itself normalized, and also that sub-trees are sorted. Here the sort is performed according to - the rank function, which is constructed "on the fly" (and is - session-dependent). See - :meth:`~sage.combinat.ordered_tree.normalize` for details. + the values of the :meth:`sort_key` method. EXAMPLES:: @@ -226,7 +248,6 @@ def normalize(self): for st in self: assert st.is_immutable(), "Subtree {} is not normalized".format(st) self._get_list().sort(key=lambda t: t.sort_key()) - # ensure unique representation self.set_immutable() @@ -686,7 +707,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): sage: LabelledRootedTree([[],[[], []]], label = 3) 3[None[], None[None[], None[]]] - Children are reordered in a session dependent order:: + Children are reordered using the value of the :meth:`sort_key` method:: sage: y = LabelledRootedTree([], label = 5); y 5[] @@ -750,9 +771,35 @@ def _auto_parent(cls): def sort_key(self): """ - Return a list of numbers and labels + Return a tuple that can be used to sort the labelled rooted trees. + + Each term is a pair (valence, label). - The tree ``self`` must be normalized before calling this ! + This tuple is in fact an encoding of the tree. The values are + the valences and labels of the vertices. The first value is + the valence of the root. Then the rest of the tuple is the + concatenation of the tuples associated to subtrees. + + The tree ``self`` must be normalized before calling this, meaning + that it subtrees have to be sorted according to their sort key. + + EXAMPLES:: + + sage: LRT = LabelledRootedTrees(); LRT + Labelled rooted trees + sage: x = LRT([], label = 3); x + 3[] + sage: x.sort_key() + ((0, 3),) + sage: y = LRT([x, x, x], label = 2); y + 2[3[], 3[], 3[]] + sage: y.sort_key() + ((3, 2), (0, 3), (0, 3), (0, 3)) + sage: LRT.an_element().sort_key() + ((3, 'alpha'), (0, 3), (1, 5), (0, None), (2, 42), (0, 3), (0, 3)) + sage: lb = RootedTrees()([[],[[], []]]).canonical_labelling() + sage: lb.sort_key() + ((2, 1), (0, 2), (2, 3), (0, 4), (0, 5)) """ l = len(self) if l == 0: @@ -761,6 +808,15 @@ def sort_key(self): return tuple(resu) def __hash__(self): + """ + Return a hash for ``self``. + + EXAMPLES:: + + sage: lb = RootedTrees()([[],[[], []]]).canonical_labelling() + sage: hash(lb) # indirect doctest + 686798862222558969 + """ return hash(self.sort_key()) _UnLabelled = RootedTree @@ -799,6 +855,7 @@ def __classcall_private__(cls, n=None): """ return LabelledRootedTrees_all() + class LabelledRootedTrees_all(LabelledRootedTrees): r""" Class of all (unordered) labelled rooted trees. @@ -866,4 +923,3 @@ def labelled_trees(self): return self Element = LabelledRootedTree - From 4234b0403bd321e9da5d64f59650f52b56074d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 19 Apr 2015 11:15:51 +0200 Subject: [PATCH 370/665] trac #11529 taking care of normalize in ordered trees, and doc --- src/sage/combinat/ordered_tree.py | 105 ++++++++++++++++++------------ src/sage/combinat/rooted_tree.py | 2 +- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index f98a1e645bf..cba226ba6e3 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -29,6 +29,7 @@ from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family +from sage.rings.infinity import Infinity class OrderedTree(AbstractClonableTree, ClonableList): @@ -246,7 +247,7 @@ def __init__(self, parent=None, children=[], check=True): if isinstance(children, str): children = eval(children) if (children.__class__ is self.__class__ and - children.parent() == parent): + children.parent() == parent): children = list(children) else: children = [self.__class__(parent, x) for x in children] @@ -274,7 +275,9 @@ def is_empty(self): def _to_binary_tree_rec(self, bijection="left"): r""" Internal recursive method to obtain a binary tree from an ordered - tree. See :meth:`to_binary_tree_left_branch` and + tree. + + See :meth:`to_binary_tree_left_branch` and :meth:`to_binary_tree_right_branch` for what it does. EXAMPLES:: @@ -292,16 +295,17 @@ def _to_binary_tree_rec(self, bijection="left"): """ from sage.combinat.binary_tree import BinaryTree root = BinaryTree() - if (bijection == "left"): + if bijection == "left": for child in self: - root = BinaryTree([root,child._to_binary_tree_rec(bijection)]) - elif (bijection == "right"): + root = BinaryTree([root, child._to_binary_tree_rec(bijection)]) + elif bijection == "right": children = list(self) children.reverse() for child in children: - root = BinaryTree([child._to_binary_tree_rec(bijection),root]) + root = BinaryTree([child._to_binary_tree_rec(bijection), root]) else: - raise ValueError("the bijection argument should be either left or right") + raise ValueError("the bijection argument should be either " + "left or right") return root @combinatorial_map(name="To binary tree, left brother = left child") @@ -437,7 +441,7 @@ def to_undirected_graph(self): relabel = True roots = [self] g.add_vertex(name=self.label()) - while len(roots)!=0: + while len(roots) != 0: node = roots.pop() for child in node: g.add_vertex(name=child.label()) @@ -448,7 +452,7 @@ def to_undirected_graph(self): return g @combinatorial_map(name="To poset") - def to_poset(self, root_to_leaf = False): + def to_poset(self, root_to_leaf=False): r""" Return the poset obtained by interpreting the tree as a hasse diagram. The default orientation is from leaves to root but you can @@ -488,11 +492,13 @@ def to_poset(self, root_to_leaf = False): relations = [] elements = [self.label()] roots = [self] - while len(roots)!=0: + while len(roots) != 0: node = roots.pop() for child in node: elements.append(child.label()) - relations.append((node.label(),child.label()) if root_to_leaf else (child.label(),node.label())) + relations.append((node.label(), child.label()) + if root_to_leaf else (child.label(), + node.label())) roots.append(child) from sage.combinat.posets.posets import Poset p = Poset([elements, relations]) @@ -500,7 +506,7 @@ def to_poset(self, root_to_leaf = False): p = p.canonical_label() return p - @combinatorial_map(order=2,name="Left-right symmetry") + @combinatorial_map(order=2, name="Left-right symmetry") def left_right_symmetry(self): r""" Return the symmetric tree of ``self`` @@ -518,8 +524,28 @@ def left_right_symmetry(self): children.reverse() return OrderedTree(children) - import sage.combinat.ranker - _unordered_ranker = sage.combinat.ranker.on_fly() + def sort_key(self): + """ + Return a tuple of numbers that can be used to sort the trees. + + This tuple is in fact an encoding of the tree. The values are + the valences of the vertices. The first value is the valence of the + root. Then the rest of the tuple is the concatenation of the tuples + associated to subtrees from left to right. + + EXAMPLES:: + + sage: RT = OrderedTree + sage: RT([[],[[]]]).sort_key() + (2, 0, 1, 0) + sage: RT([[[]],[]]).sort_key() + (2, 1, 0, 0) + """ + l = len(self) + if l == 0: + return (0,) + resu = [l] + [u for t in self for u in t.sort_key()] + return tuple(resu) @cached_method def normalize(self, inplace=False): @@ -541,15 +567,14 @@ def normalize(self, inplace=False): which picks a representative from every equivalence class with respect to the relation of "being isomorphic as unordered trees", and maps every ordered tree to the representative - chosen from its class. This map is non-deterministically - constructed based on the choices of the user. (More - specifically, it proceeds recursively by first normalizing - every subtree, and then sorting the subtrees. Here the sort is - performed according to the rank function which is constructed - "on the fly", basically sorting the trees in the order in which - they have been first encountered in the given Sage session. - See :meth:`dendrog_normalize` for a deterministic alternative - that works for unlabelled trees.) + chosen from its class. + + This map proceeds recursively by first normalizing every + subtree, and then sorting the subtrees according to the value + of the :meth:`sort_key` method. + + See also :meth:`dendrog_normalize` for an alternative + that works for unlabelled trees. Consider the quotient map `\pi` that sends a planar rooted tree to the associated unordered rooted tree. Normalization is the @@ -575,19 +600,18 @@ def normalize(self, inplace=False): sage: tb.normalize(inplace=True); tb [[], [[]]] """ - rank, unrank = self._unordered_ranker if not inplace: with self.clone() as res: resl = res._get_list() for i in range(len(resl)): resl[i] = resl[i].normalize() - resl.sort(key=rank) - return unrank(rank(res)) + resl.sort(key=lambda t: t.sort_key()) + return res else: resl = self._get_list() for i in range(len(resl)): resl[i] = resl[i].normalize() - resl.sort(key=rank) + resl.sort(key=lambda t: t.sort_key()) def dendrog_cmp(self, other): r""" @@ -675,9 +699,7 @@ def dendrog_normalize(self, inplace=False): (:meth:`dendrog_cmp`). This can be viewed as an alternative to :meth:`normalize` - for the case of unlabelled ordered rooted trees. It has the - advantage of giving path-independent results, which can be - used for doctesting output. + for the case of unlabelled ordered rooted trees. EXAMPLES:: @@ -888,6 +910,8 @@ def _element_constructor_(self, *args, **keywords): ################################################################# # Enumerated set of binary trees of a given size ################################################################# + + class OrderedTrees_size(OrderedTrees): """ The enumerated sets of binary trees of a given size @@ -909,7 +933,7 @@ def __init__(self, size): sage: TestSuite(OrderedTrees_size(0)).run() sage: for i in range(6): TestSuite(OrderedTrees_size(i)).run() """ - super(OrderedTrees_size, self).__init__(category = FiniteEnumeratedSets()) + super(OrderedTrees_size, self).__init__(category=FiniteEnumeratedSets()) self._size = size def _repr_(self): @@ -919,7 +943,7 @@ def _repr_(self): sage: OrderedTrees(3) # indirect doctest Ordered trees of size 3 """ - return "Ordered trees of size %s"%(self._size) + return "Ordered trees of size {}".format(self._size) def __contains__(self, x): """ @@ -963,7 +987,7 @@ def cardinality(self): return Integer(0) else: from combinat import catalan_number - return catalan_number(self._size-1) + return catalan_number(self._size - 1) def random_element(self): """ @@ -1014,7 +1038,7 @@ def __iter__(self): if self._size == 0: return else: - for c in Compositions(self._size-1): + for c in Compositions(self._size - 1): for lst in CartesianProduct(*(map(self.__class__, c))): yield self._element_constructor_(lst) @@ -1130,7 +1154,6 @@ def _auto_parent(cls): _UnLabelled = OrderedTree -from sage.rings.infinity import Infinity class LabelledOrderedTrees(UniqueRepresentation, Parent): """ This is a parent stub to serve as a factory class for trees with various @@ -1157,7 +1180,7 @@ def __init__(self, category=None): """ if category is None: category = Sets() - Parent.__init__(self, category = category) + Parent.__init__(self, category=category) def _repr_(self): """ @@ -1170,7 +1193,7 @@ def _repr_(self): def cardinality(self): """ - Return the cardinality of `self`. + Return the cardinality of ``self``. EXAMPLE:: @@ -1189,10 +1212,10 @@ def _an_element_(self): toto[3[], 42[3[], 3[]], 5[None[]]] """ LT = self._element_constructor_ - t = LT([], label = 3) - t1 = LT([t,t], label = 42) - t2 = LT([[]], label = 5) - return LT([t,t1,t2], label = "toto") + t = LT([], label=3) + t1 = LT([t, t], label=42) + t2 = LT([[]], label=5) + return LT([t, t1, t2], label="toto") def _element_constructor_(self, *args, **keywords): """ diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index c5760f195d1..6a56d094b39 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -32,7 +32,7 @@ def number_of_rooted_trees(n): .. math:: - a(n+1) = 1/n \sum_{k=1}^{n} ( \sum_{d|k} d a(d) ) a(n-k+1) + a(n+1) = \frac{1}{n} \sum_{k=1}^{n} \left( \sum_{d|k} d a(d) \right) a(n-k+1) EXAMPLES:: From d3e0782655dd979bb85ec3711aa14e9ad18e6dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 19 Apr 2015 11:29:58 +0200 Subject: [PATCH 371/665] trac #17944 remove duplicate norm_squared --- .../root_system/root_lattice_realizations.py | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index a83d3886c81..4fc230f3a85 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -16,7 +16,7 @@ from sage.misc.misc import attrcall from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.lazy_import import lazy_import, LazyImport +from sage.misc.lazy_import import LazyImport from sage.categories.coxeter_groups import CoxeterGroups from sage.categories.category_types import Category_over_base_ring from sage.categories.modules_with_basis import ModulesWithBasis @@ -28,6 +28,7 @@ from sage.combinat.backtrack import TransitiveIdeal, TransitiveIdealGraded from sage.combinat.root_system.plot import PlotOptions, barycentric_projection_matrix + class RootLatticeRealizations(Category_over_base_ring): r""" The category of root lattice realizations over a given base ring @@ -2179,7 +2180,6 @@ def _plot_projection_barycentric_matrix(self): (0, 0, 0) """ - from sage.matrix.constructor import matrix from sage.symbolic.constants import pi m = matrix(QQ, barycentric_projection_matrix(self.dimension()-1, angle=2*pi/3).n(20)) # We want to guarantee that the sum of the columns of the @@ -3748,7 +3748,7 @@ def extraspecial_pair(self): def height(self): r""" - Return the hieght of ``self``. + Return the height of ``self``. The height of a root `\alpha = \sum_i a_i \alpha_i` is defined to be `h(\alpha) := \sum_i a_i`. @@ -3761,29 +3761,6 @@ def height(self): """ return sum(self.coefficients()) - def norm_squared(self): - r""" - Return the norm squared of ``self``. - - Given a root `\alpha \in \Phi`, we define - - .. MATH:: - - \lVert\alpha\rVert^2 = (\alpha, \alpha) = \sum_{\beta\in\Phi} - \lvert\langle \alpha, \beta^{\vee} \rangle\rvert^2 - - where `(\alpha, \beta)` can be though of as the usual Euclidean - inner product in the ambient space. - - EXAMPLES:: - - sage: Q = RootSystem(['G', 2]).root_lattice() - sage: Q.highest_root().norm_squared() - 48 - """ - L = self.parent().root_system.ambient_space() - return L(self).scalar(L(self)) - ########################################################################## # Level ########################################################################## From e780f711afba40b34c0d11b65adaf3cc4429fac2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 19 Apr 2015 11:35:21 +0200 Subject: [PATCH 372/665] trac #18250: G.triangles_count speedup --- src/sage/graphs/base/static_dense_graph.pxd | 2 +- src/sage/graphs/base/static_dense_graph.pyx | 46 ++++++++++++++++++- src/sage/graphs/base/static_sparse_graph.pxd | 2 +- src/sage/graphs/base/static_sparse_graph.pyx | 48 ++++++++++++++++++++ src/sage/graphs/generic_graph.py | 47 +++++++++++++------ 5 files changed, 128 insertions(+), 17 deletions(-) diff --git a/src/sage/graphs/base/static_dense_graph.pxd b/src/sage/graphs/base/static_dense_graph.pxd index 8e6531a134f..acad753d261 100644 --- a/src/sage/graphs/base/static_dense_graph.pxd +++ b/src/sage/graphs/base/static_dense_graph.pxd @@ -1,4 +1,4 @@ from sage.data_structures.binary_matrix cimport binary_matrix_t - +from libc.stdint cimport uint32_t, uint64_t cdef dict dense_graph_init(binary_matrix_t m, g, translation = ?) diff --git a/src/sage/graphs/base/static_dense_graph.pyx b/src/sage/graphs/base/static_dense_graph.pyx index fe0f8d2e5bd..317ae7da284 100644 --- a/src/sage/graphs/base/static_dense_graph.pyx +++ b/src/sage/graphs/base/static_dense_graph.pyx @@ -188,8 +188,8 @@ def is_strongly_regular(g, parameters = False): return False bitset_init(b_tmp, n) - - # m i now our copy of the graph + + # m is now our copy of the graph dense_graph_init(m, g) cdef int llambda = -1 @@ -226,3 +226,45 @@ def is_strongly_regular(g, parameters = False): return (n,k,llambda,mu) else: return True + +def triangles_count(G): + r""" + Return the number of triangles in G + + INPUT: + + - `G`-- a graph + + EXAMPLE:: + + sage: from sage.graphs.base.static_dense_graph import triangles_count + sage: triangles_count(graphs.PetersenGraph()) + 0 + sage: triangles_count(graphs.CompleteGraph(15)) == binomial(15,3) + True + """ + G._scream_if_not_simple() + cdef int n = G.order() + + cdef binary_matrix_t g + dense_graph_init(g, G) + + cdef bitset_t b_tmp + bitset_init(b_tmp, n) + + cdef int i,j + cdef uint64_t count = 0 + + for i in range(n): + for j in range(i+1,n): + if not bitset_in(g.rows[i],j): + continue + bitset_and(b_tmp, g.rows[i], g.rows[j]) + count += bitset_len(b_tmp) + + bitset_free(b_tmp) + binary_matrix_free(g) + + from sage.rings.integer import Integer + return Integer(count)//3 + diff --git a/src/sage/graphs/base/static_sparse_graph.pxd b/src/sage/graphs/base/static_sparse_graph.pxd index 7d6b72e45a6..c754f25d701 100644 --- a/src/sage/graphs/base/static_sparse_graph.pxd +++ b/src/sage/graphs/base/static_sparse_graph.pxd @@ -1,5 +1,5 @@ from cpython cimport PyObject -from libc.stdint cimport uint32_t +from libc.stdint cimport uint32_t, uint64_t from sage.data_structures.bitset cimport * ctypedef unsigned short ushort ctypedef unsigned int uint diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 949300121be..3ee69ea01e8 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -493,3 +493,51 @@ def strongly_connected_components(G): free_short_digraph(g) free_short_digraph(gr) return answer + +def triangles_count(G): + r""" + Return the number of triangles in an undirected graph G + + INPUT: + + - `G`-- a graph + + EXAMPLE:: + + sage: from sage.graphs.base.static_sparse_graph import triangles_count + sage: triangles_count(graphs.PetersenGraph()) + 0 + sage: triangles_count(graphs.CompleteGraph(15)) == binomial(15,3) + True + """ + G._scream_if_not_simple() + cdef short_digraph g + init_short_digraph(g, G, edge_labelled = False) + + cdef uint64_t count = 0 + cdef uint32_t u,v,i + cdef uint32_t * p1 + cdef uint32_t * p2 + + for u in range(g.n): + for i in range(out_degree(g,u)): + v = g.neighbors[u][i] + if v<=u: + continue + + # Size of [N(u) inter N(v)]. Both are sorted lists. + p1 = g.neighbors[u] + p2 = g.neighbors[v] + while (p1 < g.neighbors[u+1] and p2 < g.neighbors[v+1]): + if p1[0] == p2[0]: + count += 1 + p1 += 1 + p2 += 1 + elif p1[0] < p2[0]: + p1 += 1 + else: + p2 += 1 + + free_short_digraph(g) + from sage.rings.integer import Integer + return Integer(count)//3 diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f06fd429f7d..22b920b8835 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12917,21 +12917,31 @@ def all_paths(self, start, end): return all_paths - def triangles_count(self, algorithm='iter'): - """ + def triangles_count(self, algorithm='sparse_copy'): + r""" Returns the number of triangles in the (di)graph. For digraphs, we count the number of directed circuit of length 3. INPUT: - - ``algorithm`` -- (default: ``'matrix'``) specifies the algorithm to + - ``algorithm`` -- (default: ``'sparse_copy'``) specifies the algorithm to use among: + - ``'sparse_copy'`` -- counts the triangles in a sparse copy of the + graph (see :mod:`sage.graphs.base.static_sparse_graph`). Calls + :func:`static_sparse_graph.triangles_count + ` + + - ``'dense_copy'`` -- counts the triangles in a dense copy of the + graph (see :mod:`sage.graphs.base.static_dense_graph`). Calls + :func:`static_dense_graph.triangles_count + ` + - ``'matrix'`` uses the trace of the cube of the adjacency matrix. - ``'iter'`` iterates over the pairs of neighbors of each - vertex. This is faster for sparse graphs. + vertex. No copy of the graph is performed EXAMPLES: @@ -12965,9 +12975,13 @@ def triangles_count(self, algorithm='iter'): sage: for i in xrange(10): # long test ... G = graphs.RandomBarabasiAlbert(50,2) - ... tm = G.triangles_count(algorithm='matrix') - ... te = G.triangles_count(algorithm='iter') - ... if tm!=te: + ... results = [] + ... results.append(G.triangles_count(algorithm='matrix')) + ... results.append(G.triangles_count(algorithm='iter')) + ... results.append(G.triangles_count(algorithm='sparse_copy')) + ... results.append(G.triangles_count(algorithm='dense_copy')) + ... if any(x != results[0] for x in results): + ... print results ... print "That's not good!" Asking for an unknown algorithm:: @@ -12980,18 +12994,25 @@ def triangles_count(self, algorithm='iter'): """ if self.is_directed(): + self._scream_if_not_simple(allow_loops=True) from sage.graphs.digraph_generators import digraphs return self.subgraph_search_count(digraphs.Circuit(3)) // 3 else: + self._scream_if_not_simple() if algorithm=='iter': - from sage.combinat.combination import Combinations tr = 0 - ggnx = self.networkx_graph() - for u in ggnx.nodes_iter(): - tr += sum(ggnx.has_edge(v,w) for v,w in Combinations(ggnx.neighbors(u),2)) - return tr//3 - + for u in self: + Nu = set(self.neighbors(u)) + for v in Nu: + tr += len(Nu.intersection(self.neighbors(v))) + return tr//6 + elif algorithm=="sparse_copy": + from sage.graphs.base.static_sparse_graph import triangles_count + return triangles_count(self) + elif algorithm=="dense_copy": + from sage.graphs.base.static_dense_graph import triangles_count + return triangles_count(self) elif algorithm=='matrix': return (self.adjacency_matrix()**3).trace() // 6 From ed8bb3c374929b2a32b3e9310124990eb5b2350c Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 19 Apr 2015 13:04:17 +0200 Subject: [PATCH 373/665] Trac 18250: documentation --- src/sage/graphs/base/static_dense_graph.pyx | 3 +-- src/sage/graphs/generic_graph.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/base/static_dense_graph.pyx b/src/sage/graphs/base/static_dense_graph.pyx index 317ae7da284..09058c44856 100644 --- a/src/sage/graphs/base/static_dense_graph.pyx +++ b/src/sage/graphs/base/static_dense_graph.pyx @@ -233,7 +233,7 @@ def triangles_count(G): INPUT: - - `G`-- a graph + - ``G``-- a simple graph EXAMPLE:: @@ -267,4 +267,3 @@ def triangles_count(G): from sage.rings.integer import Integer return Integer(count)//3 - diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 22b920b8835..8e1f0da3128 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12974,15 +12974,15 @@ def triangles_count(self, algorithm='sparse_copy'): Comparison on algorithms:: sage: for i in xrange(10): # long test - ... G = graphs.RandomBarabasiAlbert(50,2) - ... results = [] - ... results.append(G.triangles_count(algorithm='matrix')) - ... results.append(G.triangles_count(algorithm='iter')) - ... results.append(G.triangles_count(algorithm='sparse_copy')) - ... results.append(G.triangles_count(algorithm='dense_copy')) - ... if any(x != results[0] for x in results): - ... print results - ... print "That's not good!" + ....: G = graphs.RandomBarabasiAlbert(50,2) + ....: results = [] + ....: results.append(G.triangles_count(algorithm='matrix')) + ....: results.append(G.triangles_count(algorithm='iter')) + ....: results.append(G.triangles_count(algorithm='sparse_copy')) + ....: results.append(G.triangles_count(algorithm='dense_copy')) + ....: if any(x != results[0] for x in results): + ....: print results + ....: print "That's not good!" Asking for an unknown algorithm:: From 09329260aa6651aa2f30cd7d36b2427309a03159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 19 Apr 2015 13:26:28 +0200 Subject: [PATCH 374/665] trac #17944 pep8 review commit --- src/sage/combinat/root_system/root_lattice_realizations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 4fc230f3a85..77a6f6dead7 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -3740,8 +3740,8 @@ def extraspecial_pair(self): p_roots = self.parent().positive_roots_by_height() # We won't need any roots higher than us p_roots = p_roots[:p_roots.index(r)] - for i,a in enumerate(p_roots): - for b in p_roots[i+1:]: + for i, a in enumerate(p_roots): + for b in p_roots[i + 1:]: if a + b == r: return (a, b) raise ValueError("Unable to find an extraspecial pair") From fa6115dc6cdea907dad9c2cd69668f5e71660024 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 19 Apr 2015 14:36:05 +0200 Subject: [PATCH 375/665] trac #18250: Integer return type and avoid useless copies --- src/sage/graphs/base/static_sparse_graph.pyx | 7 +++++-- src/sage/graphs/generic_graph.py | 4 +--- src/sage/graphs/generic_graph_pyx.pyx | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 3ee69ea01e8..915bb2265de 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -160,6 +160,7 @@ cimport cpython from sage.graphs.base.c_graph cimport CGraph from libc.stdint cimport INT32_MAX +from static_sparse_backend cimport StaticSparseCGraph cdef int init_short_digraph(short_digraph g, G, edge_labelled = False) except -1: r""" @@ -511,8 +512,11 @@ def triangles_count(G): True """ G._scream_if_not_simple() + + # g is a copy of G. If G is internally a static sparse graph, we use it. cdef short_digraph g - init_short_digraph(g, G, edge_labelled = False) + G = G.copy(immutable=True) + g[0] = ( (G._backend._cg)).g[0] cdef uint64_t count = 0 cdef uint32_t u,v,i @@ -538,6 +542,5 @@ def triangles_count(G): else: p2 += 1 - free_short_digraph(g) from sage.rings.integer import Integer return Integer(count)//3 diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 8e1f0da3128..928a4a190f3 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12997,7 +12997,6 @@ def triangles_count(self, algorithm='sparse_copy'): self._scream_if_not_simple(allow_loops=True) from sage.graphs.digraph_generators import digraphs return self.subgraph_search_count(digraphs.Circuit(3)) // 3 - else: self._scream_if_not_simple() if algorithm=='iter': @@ -13006,7 +13005,7 @@ def triangles_count(self, algorithm='sparse_copy'): Nu = set(self.neighbors(u)) for v in Nu: tr += len(Nu.intersection(self.neighbors(v))) - return tr//6 + return Integer(tr//6) elif algorithm=="sparse_copy": from sage.graphs.base.static_sparse_graph import triangles_count return triangles_count(self) @@ -13015,7 +13014,6 @@ def triangles_count(self, algorithm='sparse_copy'): return triangles_count(self) elif algorithm=='matrix': return (self.adjacency_matrix()**3).trace() // 6 - else: raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 7ba71c128ea..42023f8770b 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -571,7 +571,8 @@ cdef class SubgraphSearch: for _ in self: i+=1 - return i + from sage.rings.integer import Integer + return Integer(i) def _initialization(self): r""" From fd88c98cfc2fee8d0750cd9b6f88d1d7b8177ed4 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 19 Apr 2015 15:54:35 +0200 Subject: [PATCH 376/665] trac #18250: algorithm=None by default and better 'wrong values' check --- src/sage/graphs/generic_graph.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 928a4a190f3..7d28eb54280 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12917,7 +12917,7 @@ def all_paths(self, start, end): return all_paths - def triangles_count(self, algorithm='sparse_copy'): + def triangles_count(self, algorithm=None): r""" Returns the number of triangles in the (di)graph. @@ -12925,8 +12925,8 @@ def triangles_count(self, algorithm='sparse_copy'): INPUT: - - ``algorithm`` -- (default: ``'sparse_copy'``) specifies the algorithm to - use among: + - ``algorithm`` -- (default: ``None``) specifies the algorithm to use + (note that only ``'iter'`` is available for directed graphs): - ``'sparse_copy'`` -- counts the triangles in a sparse copy of the graph (see :mod:`sage.graphs.base.static_sparse_graph`). Calls @@ -12940,8 +12940,12 @@ def triangles_count(self, algorithm='sparse_copy'): - ``'matrix'`` uses the trace of the cube of the adjacency matrix. - - ``'iter'`` iterates over the pairs of neighbors of each - vertex. No copy of the graph is performed + - ``'iter'`` iterates over the pairs of neighbors of each vertex. No + copy of the graph is performed + + - ``None`` -- for undirected graphs, uses ``"sparse_copy"`` or + ``"dense_copy"`` depending on whether the graph is stored as dense + or sparse. For directed graphs, uses ``'iter'``. EXAMPLES: @@ -12991,14 +12995,26 @@ def triangles_count(self, algorithm='sparse_copy'): Traceback (most recent call last): ... ValueError: Algorithm 'tip top' not yet implemented. Please contribute. - + sage: digraphs.Path(5).triangles_count(algorithm="sparse_copy") + Traceback (most recent call last): + ... + ValueError: The value of algorithm(=sparse_copy) must be 'iter' or None for direcetd graphs """ if self.is_directed(): + if algorithm is not None and algorithm != "iter": + raise ValueError("The value of algorithm(={}) must be 'iter' " + "or None for direcetd graphs".format(algorithm)) + self._scream_if_not_simple(allow_loops=True) from sage.graphs.digraph_generators import digraphs return self.subgraph_search_count(digraphs.Circuit(3)) // 3 else: self._scream_if_not_simple() + if algorithm is None: + from sage.graphs.base.dense_graph import DenseGraphBackend + algorithm = ('dense_copy' if isinstance(self._backend, DenseGraphBackend) else + 'sparse_copy') + if algorithm=='iter': tr = 0 for u in self: From 88b7d4fbd02599726e9f9ed2c821a20bb00181cc Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 22 Jan 2015 18:55:03 +0100 Subject: [PATCH 377/665] trac #17662: database of EDS --- src/sage/combinat/designs/database.py | 310 +++++++++++++++++- .../combinat/designs/difference_family.py | 56 +++- 2 files changed, 352 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 5b219995167..4f06bc87eae 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -30,6 +30,9 @@ - `(n,k;\lambda,\mu;u)`-quasi-difference matrices: {LIST_OF_QDM} +- `(q,k)` evenly distributed sets +{LIST_OF_EDS} + REFERENCES: .. [DesignHandbook] Handbook of Combinatorial Designs (2ed) @@ -4126,6 +4129,307 @@ def RBIBD_120_8_1(): (120,8,1): RBIBD_120_8_1, } +# Evenly Distributed Sets (EDS) +# +# For the definition see the documentation of the class +# EvenlyDistributedSetsBacktracker in the file evenly_distributed_sets.pyx +# +# EDS is a dictionnary of dictionnaries whose keys are the integers +# 4, 5,..., 10. For each k in {4,...,10} the keys of EDS[k] are the prime powers +# `q` so that `q = 1 modulo k(k-1)`. +# The value at position EDS[k][q] is one of: +# - ``False`` if there is no `(q,k)`-evenly distributed set +# - ``(None, B)`` if `q` is prime and `B` is an evenly distributed set in Z/pZ +# - ``(poly, B)`` if `q=p^k` is a prime power (but not a prime). The +# polynomial ``poly`` is such that GF(p)[x] / (poly) is a finite field of +# cardinality q. The set `B` is then given in terms of the canonical +# generator `x`. + +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer_ring import ZZ +R = PolynomialRing(ZZ,'a') +a = R.gen() + +EDS={ +4:{ + 13: (None, [0, 1, 11, 5]), + 25: (a**2 + 4*a + 2, [0, 1, a, 3*a + 4]), + 37: (None, [0, 1, 17, 30]), + 49: (a**2 + 6*a + 3, [0, 1, a + 6, 4*a + 1]), + 61: (None, [0, 1, 6, 37]), + 73: (None, [0, 1, 5, 18]), + 97: (None, [0, 1, 5, 24]), + 109: (None, [0, 1, 6, 60]), + 121: (a**2 + 7*a + 2, [0, 1, 2*a, 3*a + 7]), + 157: (None, [0, 1, 20, 132]), + 169: (a**2 + 12*a + 2, [0, 1, a + 12, a + 6]), + 181: (None, [0, 1, 10, 87]), + 193: (None, [0, 1, 5, 11]), + 229: (None, [0, 1, 6, 13]), + 241: (None, [0, 1, 11, 24]), + 277: (None, [0, 1, 11, 228]), + 289: (a**2 + 16*a + 3, [0, 1, a, 6*a + 13]), + 313: (None, [0, 1, 10, 121]), + 337: (None, [0, 1, 10, 21]), + 349: (None, [0, 1, 7, 19]), + 361: (a**2 + 18*a + 2, [0, 1, a + 3, 9*a + 5]), + 373: (None, [0, 1, 5, 231]), + 397: (None, [0, 1, 18, 11]), + 409: (None, [0, 1, 21, 60]), + 421: (None, [0, 1, 14, 31]), + 433: (None, [0, 1, 10, 97]), + 457: (None, [0, 1, 13, 195]), + 529: (a**2 + 21*a + 5, [0, 1, a + 5, 3*a + 11]), + 541: (None, [0, 1, 11, 45]), + 577: (None, [0, 1, 5, 115]), + 601: (None, [0, 1, 7, 69]), + 613: (None, [0, 1, 6, 88]), + 625: (a**4 + 4*a**2 + 4*a + 2, [0, 1, a + 3, 2*a**2 + a]), + 661: (None, [0, 1, 6, 66]), + 673: (None, [0, 1, 5, 46]), + 709: (None, [0, 1, 17, 256]), + 733: (None, [0, 1, 6, 49]), + 757: (None, [0, 1, 5, 224]), + 769: (None, [0, 1, 11, 79]), + 829: (None, [0, 1, 19, 44]), + 841: (a**2 + 24*a + 2, [0, 1, a + 8, 4*a + 27]), + 853: (None, [0, 1, 6, 58]), + 877: (None, [0, 1, 5, 46]), + 937: (None, [0, 1, 5, 160]), + 961: (a**2 + 29*a + 3, [0, 1, a + 16, 3*a + 8]), + 997: (None, [0, 1, 7, 102]), + 1009: (None, [0, 1, 11, 131]), + 1021: (None, [0, 1, 19, 153]), + 1033: (None, [0, 1, 5, 15]), + 1069: (None, [0, 1, 6, 36]), + 1093: (None, [0, 1, 15, 25]), + 1117: (None, [0, 1, 6, 23]), + 1129: (None, [0, 1, 11, 37]), + 1153: (None, [0, 1, 5, 151]), + 1201: (None, [0, 1, 17, 48]), + 1213: (None, [0, 1, 20, 217]), + 1237: (None, [0, 1, 7, 199]), + 1249: (None, [0, 1, 7, 36]), + 1297: (None, [0, 1, 10, 103]), + 1321: (None, [0, 1, 7, 112]), + 1369: (a**2 + 33*a + 2, [0, 1, a + 33, a + 9]), + 1381: (None, [0, 1, 19, 84]), + 1429: (None, [0, 1, 14, 116]), + 1453: (None, [0, 1, 5, 377]), + 1489: (None, [0, 1, 14, 44]), + 1549: (None, [0, 1, 22, 89]), + 1597: (None, [0, 1, 33, 228]), + 1609: (None, [0, 1, 7, 95]), + 1621: (None, [0, 1, 6, 165]), + 1657: (None, [0, 1, 11, 121]), + 1669: (None, [0, 1, 6, 155]), + 1681: (a**2 + 38*a + 6, [0, 1, a, 6*a + 6]), + 1693: (None, [0, 1, 5, 50]), + 1741: (None, [0, 1, 19, 341]), + 1753: (None, [0, 1, 7, 146]), + 1777: (None, [0, 1, 10, 100]), + 1789: (None, [0, 1, 6, 238]), + 1801: (None, [0, 1, 11, 79]), + 1849: (a**2 + 42*a + 3, [0, 1, a + 5, 2*a + 35]), + 1861: (None, [0, 1, 18, 110]), + 1873: (None, [0, 1, 10, 40]), + 1933: (None, [0, 1, 14, 100]), + 1993: (None, [0, 1, 5, 34]), + 2017: (None, [0, 1, 10, 57]), + 2029: (None, [0, 1, 6, 25]), + 2053: (None, [0, 1, 14, 95]), + 2089: (None, [0, 1, 7, 66]), + 2113: (None, [0, 1, 7, 117]), + 2137: (None, [0, 1, 10, 60]), + 2161: (None, [0, 1, 31, 78]), + 2197: (a**3 + 2*a + 11, [0, 1, 2*a + 9, 11*a + 3]), + 2209: (a**2 + 45*a + 5, [0, 1, a + 5, 2*a + 12]), + 2221: (None, [0, 1, 18, 201]), + 2269: (None, [0, 1, 6, 99]), + 2281: (None, [0, 1, 7, 212]), + 2293: (None, [0, 1, 5, 116]), + 2341: (None, [0, 1, 7, 99]), + 2377: (None, [0, 1, 5, 214]), + 2389: (None, [0, 1, 18, 29]), + 2401: (a**4 + 5*a**2 + 4*a + 3, [0, 1, a, 2*a**2 + 6]), + 2437: (None, [0, 1, 5, 45]), + 2473: (None, [0, 1, 5, 298]), + 2521: (None, [0, 1, 17, 150]), + 2557: (None, [0, 1, 5, 68]), + 2593: (None, [0, 1, 7, 255]), + 2617: (None, [0, 1, 5, 11]), + 2677: (None, [0, 1, 7, 57]), + 2689: (None, [0, 1, 19, 115]), + 2713: (None, [0, 1, 5, 139]), + 2749: (None, [0, 1, 13, 243]), + 2797: (None, [0, 1, 5, 95]), + 2809: (a**2 + 49*a + 2, [0, 1, a, 3*a + 22])}, + +5: { + 41: (None, [0, 1, 13, 38, 31]), + 61: (None, [0, 1, 26, 11, 7]), + 81: False, + 101: (None, [0, 1, 12, 43, 81]), + 121: (a**2 + 7*a + 2, [0, 1, a, 9*a + 5, 3*a + 1]), + 181: (None, [0, 1, 21, 47, 123]), + 241: (None, [0, 1, 7, 51, 189]), + 281: (None, [0, 1, 3, 143, 74]), + 361: (a**2 + 18*a + 2, [0, 1, a, 2*a + 14, 18*a + 9]), + 401: (None, [0, 1, 3, 128, 133]), + 421: (None, [0, 1, 40, 132, 8]), + 461: (None, [0, 1, 28, 53, 287]), + 521: (None, [0, 1, 3, 9, 217]), + 541: (None, [0, 1, 30, 124, 370]), + 601: (None, [0, 1, 7, 10, 545]), + 641: (None, [0, 1, 12, 79, 185]), + 661: (None, [0, 1, 6, 36, 286]), + 701: (None, [0, 1, 12, 97, 365]), + 761: (None, [0, 1, 11, 4, 260]), + 821: (None, [0, 1, 13, 62, 571]), + 841: (a**2 + 24*a + 2, [0, 1, a, 2*a + 5, 5*a + 19]), + 881: (None, [0, 1, 3, 9, 836]), + 941: (None, [0, 1, 7, 49, 96]), + 961: (a**2 + 29*a + 3, [0, 1, a, 3, 3*a]), + 1021: (None, [0, 1, 30, 6, 171]), + 1061: (None, [0, 1, 15, 51, 60]), + 1181: (None, [0, 1, 7, 90, 87]), + 1201: (None, [0, 1, 11, 14, 621]), + 1301: (None, [0, 1, 7, 19, 138]), + 1321: (None, [0, 1, 13, 5, 1168]), + 1361: (None, [0, 1, 3, 9, 159]), + 1381: (None, [0, 1, 26, 35, 547]), + 1481: (None, [0, 1, 3, 9, 730]), + 1601: (None, [0, 1, 3, 17, 1077]), + 1621: (None, [0, 1, 14, 4, 1380]), + 1681: (a**2 + 38*a + 6, [0, 1, a, a + 15, 40*a + 22]), + 1721: (None, [0, 1, 3, 121, 687]), + 1741: (None, [0, 1, 7, 29, 32]), + 1801: (None, [0, 1, 11, 51, 142]), + 1861: (None, [0, 1, 10, 62, 643]), + 1901: (None, [0, 1, 12, 4, 477]) + }, + +6: { + 31: (None, [0, 1, 3, 12, 18, 8]), + 61: False, + 121: False, + 151: (None, [0, 1, 69, 36, 57, 89]), + 181: (None, [0, 1, 14, 4, 59, 139]), + 211: (None, [0, 1, 24, 141, 128, 202]), + 241: (None, [0, 1, 7, 151, 232, 136]), + 271: (None, [0, 1, 6, 15, 81, 225]), + 331: (None, [0, 1, 29, 113, 21, 69]), + 361: (a**2 + 18*a + 2, [0, 1, a, 3*a + 2, 14*a, 10*a + 9]), + 421: (None, [0, 1, 11, 4, 111, 394]), + 541: (None, [0, 1, 5, 42, 157, 322]), + 571: (None, [0, 1, 3, 52, 549, 137]), + 601: (None, [0, 1, 6, 114, 490, 359]), + 631: (None, [0, 1, 3, 73, 144, 466]), + 661: (None, [0, 1, 6, 73, 182, 44]), + 691: (None, [0, 1, 3, 9, 554, 425]), + 751: (None, [0, 1, 3, 9, 314, 226]), + 811: (None, [0, 1, 3, 9, 504, 341]), + 841: (a**2 + 24*a + 2, [0, 1, a, 3*a + 11, 12*a + 24, 22*a + 10]), + 961: (a**2 + 29*a + 3, [0, 1, 11, 28, 15*a + 25, 4*a + 3]), + 991: (None, [0, 1, 6, 36, 234, 834]), + 1021: (None, [0, 1, 30, 6, 476, 154]), + 1051: (None, [0, 1, 7, 23, 324, 266]), + 1171: (None, [0, 1, 37, 4, 1163, 302]), + 1201: (None, [0, 1, 11, 5, 130, 146]), + 1231: (None, [0, 1, 3, 9, 768, 476]), + 1291: (None, [0, 1, 45, 79, 320, 390]), + 1321: (None, [0, 1, 13, 33, 445, 894]), + 1381: (None, [0, 1, 26, 56, 474, 839]), + 1471: (None, [0, 1, 6, 36, 425, 676]), + 1531: (None, [0, 1, 38, 8, 465, 1376]), + 1621: (None, [0, 1, 5, 20, 117, 1486]), + 1681: (a**2 + 38*a + 6, [0, 1, a, a + 5, 2*a + 28, 2*a + 34]), + 1741: (None, [0, 1, 9, 4, 301, 420]), + 1801: (None, [0, 1, 6, 4, 1263, 260]), + 1831: (None, [0, 1, 3, 9, 452, 1532]), + 1861: (None, [0, 1, 10, 4, 188, 1405]), + 1951: (None, [0, 1, 3, 7, 27, 1032]), + }, + +7: { + 43: False, + 127: False, + 169: (a**2 + 12*a + 2, [0, 1, a, 5*a + 3, 11*a + 10, 11*a + 6, 5*a + 6]), + 211: False, + 337: (None, [0, 1, 10, 28, 80, 224, 129]), + 379: (None, [0, 1, 9, 175, 287, 14, 271]), + 421: (None, [0, 1, 26, 4, 191, 250, 298]), + 463: (None, [0, 1, 3, 9, 310, 243, 415]), + 547: (None, [0, 1, 25, 4, 430, 9, 210]), + 631: (None, [0, 1, 3, 104, 303, 257, 447]), + 673: (None, [0, 1, 5, 25, 405, 476, 131]), + 757: (None, [0, 1, 6, 36, 232, 557, 274]), + 841: (a**2 + 24*a + 2, [0, 1, a + 28, 2*a + 1, 7*a + 22, 25*a + 20, 11*a + 10]), + 883: (None, [0, 1, 54, 4, 870, 638, 310]), + 967: (None, [0, 1, 5, 22, 775, 577, 819]), + 1009: (None, [0, 1, 5, 36, 911, 650, 412]), + 1051: (None, [0, 1, 7, 49, 274, 1012, 213]), + 1093: (None, [0, 1, 5, 25, 274, 214, 735]), + 1303: (None, [0, 1, 30, 70, 1107, 39, 1271]), + 1429: (None, [0, 1, 6, 15, 289, 975, 314]), + 1471: (None, [0, 1, 6, 36, 216, 947, 568]), + 1597: (None, [0, 1, 7, 38, 266, 223, 1316]), + 1681: (a**2 + 38*a + 6, [0, 1, a, 2*a + 12, 7*a + 9, 35*a + 29, 33*a + 2]), + 1723: (None, [0, 1, 3, 9, 1169, 420, 1651]), + 1849: (a**2 + 42*a + 3, [0, 1, 13, 3, 39, 19, 5*a + 13]), + 1933: (None, [0, 1, 5, 25, 319, 1607, 1782]) + }, + +8: { + 113: False, + 169: False, + 281: False, + 337: False, + 449: (None, [0, 1, 3, 332, 8, 104, 381, 61]), + 617: (None, [0, 1, 3, 610, 397, 318, 465, 84]), + 673: (None, [0, 1, 20, 355, 92, 491, 315, 478]), + 729: (a**6 + 2*a**4 + a**2 + 2*a + 2, [0, 1, a, + a**2, 2*a**4 + a**3 + a**2 + a + 1, + a**4, a**3 + 2*a**2 + 2, 2*a**5 + a**4 + 2*a**2 + 2*a]), + 841: (a**2 + 24*a + 2, [0, 1, a, 27, 27*a + 25, 5*a + 18, + 11*a + 14, 14*a + 2]), + 953: (None, [0, 1, 3, 36, 727, 636, 899, 448]), + 1009: (None, [0, 1, 11, 20, 202, 283, 698, 629]), + 1289: (None, [0, 1, 6, 133, 579, 793, 361, 658]), + 1681: (a**2 + 38*a + 6, [0, 1, a, 3*a + 25, 5*a + 33, 34*a + 12, + 23*a + 31, 38*a + 14]), + 1849: (a**2 + 42*a + 3, [0, 1, a, a + 2, 4*a + 36, 5*a, + 20*a + 22, 18*a + 5]), + }, + +9: { + 73: (None, [0, 1, 5, 21, 59, 18, 12, 51, 49]), + 289: False, + 361: False, + 433: (None, [0, 1, 5, 145, 347, 248, 57, 267, 110]), + 577: False, + 937: (None, [0, 1, 5, 265, 828, 773, 328, 587, 866]), + 1009: (None, [0, 1, 11, 251, 944, 497, 700, 99, 545]), + 1153: (None, [0, 1, 5, 522, 1116, 495, 215, 859, 167]), + 1297: (None, [0, 1, 10, 244, 30, 1111, 392, 1183, 123]), + 1369: (a**2 + 33*a + 2, [0, 1, a, 8*a + 34, 36*a + 33, 2*a + 21, 20, + 32*a + 15, 25*a + 20]), + 1657: (None, [0, 1, 11, 121, 396, 269, 266, 873, 345]), + 1801: (None, [0, 1, 11, 105, 603, 966, 746, 1585, 1298]), + 1873: (None, [0, 1, 10, 32, 1837, 1823, 1040, 1826, 1496]), + }, + +10:{ + 991: False, + 1171: (None, [0, 1, 817, 856, 143, 881, 833, 82, 870, 564]), + 1531: (None, [0, 1, 61, 1109, 417, 590, 1273, 11, 1445, 326]), + 1621: (None, [0, 1, 52, 111, 779, 365, 1225, 378, 535, 1012]), + 1801: (None, [0, 1, 6, 369, 80, 1717, 138, 1782, 1301, 82]), + } +} + +LIST_OF_EDS = ("\n".join(" - `k = {}`: {}".format( + k, ', '.join('`{}`'.format(q) for q in sorted(EDS[k]) if EDS[k][q] is not False)) for k in sorted(EDS))) __doc__ = __doc__.format( LIST_OF_OA_CONSTRUCTIONS = LIST_OF_OA_CONSTRUCTIONS, @@ -4133,5 +4437,7 @@ def RBIBD_120_8_1(): LIST_OF_VMT_VECTORS = LIST_OF_VMT_VECTORS, LIST_OF_DF = LIST_OF_DF, LIST_OF_DM = LIST_OF_DM, - LIST_OF_QDM = LIST_OF_QDM) -del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS, LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM + LIST_OF_QDM = LIST_OF_QDM, + LIST_OF_EDS = LIST_OF_EDS) +del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS,LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM, LIST_OF_EDS +del PolynomialRing, ZZ, a, diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 26d8c51ae9d..76d6ac7514d 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -1022,14 +1022,15 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: G Finite Field of size 73 sage: D - [[0, 1, 8, 64], - [0, 2, 16, 55], - [0, 3, 24, 46], - [0, 25, 54, 67], - [0, 35, 50, 61], - [0, 36, 41, 69]] + [[0, 1, 5, 18], + [0, 3, 15, 54], + [0, 9, 45, 16], + [0, 27, 62, 48], + [0, 8, 40, 71], + [0, 24, 47, 67]] + sage: print designs.difference_family(73, 4, explain_construction=True) - Radical difference family on a finite field + The database contains a (73,4)-evenly distributed set sage: G,D = designs.difference_family(15,7,3) sage: G @@ -1067,9 +1068,9 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: for q in islice(prime_power_mod(1,42), 60): ....: l7[designs.difference_family(q,7,existence=True)].append(q) sage: l7[True] - [337, 421, 463, 883, 1723, 3067, 3319, 3529, 3823, 3907, 4621, 4957, 5167] + [169, 337, 379, 421, 463, 547, 631, 673, 757, 841, 883, 967, ..., 4621, 4957, 5167] sage: l7[Unknown] - [43, 127, 169, 211, ..., 4999, 5041, 5209] + [43, 127, 211, 2017, 2143, 2269, 2311, 2437, 2521, 2647, ..., 4999, 5041, 5209] sage: l7[False] [] @@ -1124,7 +1125,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch 55: (3,1), (9,4) 57: (3,1), (7,3), (8,1) 59: (2,1) - 61: (2,1), (3,1), (3,2), (4,3), (5,1), (5,4), (6,2), (6,3), (6,5) + 61: (2,1), (3,1), (3,2), (4,1), (4,3), (5,1), (5,4), (6,2), (6,3), (6,5) 63: (3,1) 64: (3,2), (4,1), (7,2), (7,6), (9,8) 65: (5,1) @@ -1175,10 +1176,18 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch Check the database:: - sage: from sage.combinat.designs.database import DF + sage: from sage.combinat.designs.database import DF,EDS sage: for v,k,l in DF: + ....: assert designs.difference_family(v,k,l,existence=True) is True ....: df = designs.difference_family(v,k,l,check=True) + sage: for k in EDS: + ....: for v in EDS[k]: + ....: if EDS[k][v] is False: + ....: continue + ....: assert designs.difference_family(v,k,1,existence=True) is True + ....: df = designs.difference_family(v,k,1,check=True) + Check a failing construction (:trac:`17528`):: sage: designs.difference_family(9,3) @@ -1194,7 +1203,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch """ from block_design import are_hyperplanes_in_projective_geometry_parameters - from database import DF + from database import DF, EDS if (v,k,l) in DF: if existence: @@ -1221,6 +1230,29 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return G,df + elif l == 1 and k in EDS and v in EDS[k] and EDS[k][v] is not False: + if existence: + return True + elif explain_construction: + return "The database contains a ({},{})-evenly distributed set".format(v,k) + + from sage.rings.finite_rings.constructor import GF + poly,B = EDS[k][v] + if poly is None: # q is prime + K = G = GF(v) + else: + K = G = GF(v,'a',modulus=poly) + + B = map(K,B) + e = k*(k-1)/2 + xe = G.multiplicative_generator()**e + df = [[xe**j*b for b in B] for j in range((v-1)/(2*e))] + if check and not is_difference_family(G, df, v=v, k=k, l=l): + raise RuntimeError("There is an invalid ({},{})-evenly distributed " + "set in the database... Please contact " + "sage-devel@googlegroups.com".format(v,k,l)) + return G,df + e = k*(k-1) if (l*(v-1)) % e: if existence: From 2ede6d67fd53d503d522d022a548cb8f35e08ef7 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 22 Jan 2015 18:55:25 +0100 Subject: [PATCH 378/665] trac #17662: EDS backtracker --- src/module_list.py | 3 + .../designs/evenly_distributed_sets.pyx | 513 ++++++++++++++++++ 2 files changed, 516 insertions(+) create mode 100644 src/sage/combinat/designs/evenly_distributed_sets.pyx diff --git a/src/module_list.py b/src/module_list.py index d4db0acf81d..c77d594e9fc 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -241,6 +241,9 @@ def uname_specific(name, value, alternative): Extension('sage.combinat.designs.orthogonal_arrays_find_recursive', sources=['sage/combinat/designs/orthogonal_arrays_find_recursive.pyx']), + Extension('sage.combinat.designs.evenly_distributed_sets', + sources=['sage/combinat/designs/evenly_distributed_sets.pyx']), + ################################ ## ## sage.crypto diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx new file mode 100644 index 00000000000..85dd25438ab --- /dev/null +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -0,0 +1,513 @@ +r""" +Evenly distributed sets in finite fields + +This module consists of a simple class :class:`EvenlyDistributedSetsBacktracker`. Its main +purpose is to iterate through the evenly distributed sets of a given finite +field. + +The naive backtracker implemented here is not directly used to generate +difference family as even for small parameters it already takes time to run. +Instead, its output has been stored into a database +:mod:`sage.combinat.designs.database`. If the backtracker is improved, then one +might want to update this database with more values. +""" + +include "sage/ext/stdsage.pxi" + +cimport cython + +from libc.limits cimport UINT_MAX +from libc.string cimport memset +from libc.stdlib cimport qsort + +from sage.ext.memory cimport check_malloc +from sage.libs.gmp.types cimport mpz_t + +from sage.rings.integer cimport Integer,smallInteger + +cdef class EvenlyDistributedSetsBacktracker: + r""" + Set of evenly distributed subsets in finite fields. + + Let `K` be a finite field of cardinality `q` and `k` an integer so that + `k(k-1)` divides `q-1`. Let `H = K^*` be the multiplicative group of + invertible elements in `K`. A `k`-*evenly distributed set* in `K` is a set + `B = \{b_1, b_2, \ldots, b_k\}` of `k` elements of `K` so that the `k(k-1)` + differences `\Delta B = \{b_i - b_j; i \not= j\}` fill each coset modulo + `H^{2(q-1)/(k(k-1))}` exactly twice. + + Evenly distributed sets were introduced by Wilson [Wi72]_. He proved that + for any `k`, and for any prime power `q` large enough such that `k(k-1)` + divides `k` there exists a `k`-evenly distributed set in the field of + cardinality `q`. This existence result based on a counting argument does + not provide a simple method to generate them. + + From a `k`-evenly distributed set, it is straightforward to build a + `(q,k,1)`-difference family. Another approach to generate difference family, + somehow dual to this one, is via radical difference family (see in + particular + :func:`~sage.combinat.designs.difference_family.radical_difference_family` + from the module :mod:`~sage.combinat.designs.difference_family`). + + INPUT: + + - ``K`` -- a finite field of cardinality `q` + + - ``k`` -- a positive integer such that `k(k-1)` divides `q-1` + + - ``up_to_isomorphism`` - (boolean, default ``True``) whether only consider + evenly distributed set up to automorphisms of the field of the form + `x \mapsto ax + b`. + + - ``check`` -- boolean (default is ``False``). Whether you want to check + intermediate steps of the iterator. This is mainly intended for debugging + purpose. Setting it to ``True`` will considerably slow the iteration. + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + The main part of the code is contained in the iterator. To get one evenly + distributed set just do:: + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(151),6) + sage: B = E.an_element() + sage: B + [0, 1, 69, 36, 57, 89] + + The class has a method to convert it to a difference family:: + + sage: E.to_difference_family(B) + [[0, 1, 69, 36, 57, 89], + [0, 132, 48, 71, 125, 121], + [0, 59, 145, 10, 41, 117], + [0, 87, 114, 112, 127, 42], + [0, 8, 99, 137, 3, 108]] + + It is also possible to run over all evenly distributed sets:: + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=False) + sage: for B in E: print B + [0, 1, 11, 5] + [0, 1, 4, 6] + [0, 1, 9, 3] + [0, 1, 8, 10] + + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=True) + sage: for B in E: print B + [0, 1, 11, 5] + """ + # PYTHON DATA + cdef K # the underlying field + cdef list list_K # the elements of K (i -> x) + cdef dict K_to_int # inverse of list_K (x -> i) + + # FLAGS + cdef int count # do we count or do we iterate + cdef int check # do we need to check (debug) + cdef int up_to_isom # do we care only about isomorphisms + + # STATIC DATA + cdef unsigned int q # cardinality of the field + cdef unsigned int k # size of the subsets + cdef unsigned int e # k(k-1)/2 + cdef unsigned int ** diff # qxq array: diff[x][y] = x - y + cdef unsigned int ** ratio # qxq array: ratio[x][y] = x / y + + # DYNAMIC DATA + cdef unsigned int * B # current stack of elements of {0,...,q-1} + cdef unsigned int * cosets # cosets of differences of elts in B + cdef unsigned int * t # temporary variable for updates + + def __dealloc__(self): + if self.diff != NULL: + sage_free(self.diff[0]) + sage_free(self.diff) + if self.ratio != NULL: + sage_free(self.ratio[0]) + sage_free(self.ratio) + sage_free(self.B) + sage_free(self.cosets) + sage_free(self.t) + + def __init__(self, K, k, up_to_isomorphism=True, check=False): + r""" + TESTS:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + sage: EvenlyDistributedSetsBacktracker(Zmod(4),2) + Traceback (most recent call last): + ... + ValueError: Ring of integers modulo 4 is not a field + + sage: EvenlyDistributedSetsBacktracker(Zmod(71),7) + Traceback (most recent call last): + ... + ValueError: k(k-1)=42 does not divide q-1=71 + """ + self.check = 1 if check else 0 + self.up_to_isom = 1 if up_to_isomorphism else 0 + self.count = 0 + + cdef unsigned int i,j,ell + + if not K.is_field(): + raise ValueError("{} is not a field".format(K)) + cdef unsigned int q = K.cardinality() + cdef unsigned int e = k*(k-1)/2 + if (q-1) % (2*e) != 0: + raise ValueError("k(k-1)={} does not divide q-1={}".format(k*(k-1),q)) + cdef unsigned int m = (q-1)/e + + self.q = q + self.e = e + self.k = k + self.K = K + + self.diff = check_malloc(q*sizeof(unsigned int *)) + self.diff[0] = check_malloc(q*q*sizeof(unsigned int)) + for i in range(1,self.q): + self.diff[i] = self.diff[i-1] + q + self.ratio = check_malloc(q*sizeof(unsigned int *)) + self.ratio[0] = check_malloc(q*q*sizeof(unsigned int)) + for i in range(1,self.q): + self.ratio[i] = self.ratio[i-1] + q + + self.B = check_malloc(k*sizeof(unsigned int)) + self.cosets = check_malloc(e*sizeof(unsigned int)) + self.t = check_malloc(e*sizeof(unsigned int)) + + x = K.multiplicative_generator() + list_K = [] + for i in range(e): + list_K.extend(sorted(x**(j*e+i) for j in range(m))) + list_K.append(K.zero()) + self.list_K = list_K + K_to_int = self.K_to_int = {y:i for i,y in enumerate(list_K)} + assert self.K_to_int[K.zero()] == q-1 + assert self.K_to_int[K.one()] == 0 + assert set(K) == set(list_K) + + for i,x in enumerate(self.list_K): + for j,y in enumerate(self.list_K): + self.diff[i][j] = K_to_int[x-y] + if y: + self.ratio[i][j] = K_to_int[x/y] + else: + self.ratio[i][j] = UINT_MAX + + def to_difference_family(self, B): + r""" + Given an evenly distributed set ``B`` convert it to a difference family. + + This is useful if you want to obtain the difference family from the + output of the iterator. + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + sage: E = EvenlyDistributedSetsBacktracker(Zmod(41),5) + sage: B = E.an_element(); B + [0, 1, 13, 38, 31] + sage: D = E.to_difference_family(B); D + [[0, 1, 13, 38, 31], [0, 32, 6, 27, 8]] + + sage: from sage.combinat.designs.difference_family import is_difference_family + sage: is_difference_family(Zmod(41),D,41,5,1) + True + """ + xe = self.K.multiplicative_generator() ** (self.e) + return [[xe**j*b for b in B] for j in range((self.q-1)/(2*self.e))] + + def an_element(self): + r""" + Return an evenly distributed set. + + If there is no such subset raise an ``EmptySetError``. + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(41),5) + sage: E.an_element() + [0, 1, 13, 38, 31] + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(61),6) + sage: E.an_element() + Traceback (most recent call last): + ... + EmptySetError: no 6-evenly distributed set in Ring of integers modulo 61 + """ + from sage.categories.sets_cat import EmptySetError + it = iter(self) + try: + B = it.next() + except StopIteration: + raise EmptySetError("no {}-evenly distributed set in {}".format(self.k,self.K)) + return B + + def __repr__(self): + r""" + A string representative. + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + sage: EvenlyDistributedSetsBacktracker(GF(25,'a'), 4) + 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 + sage: EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, up_to_isomorphism=False) + 4-evenly distributed sets in Finite Field in a of size 5^2 + """ + return "{}-evenly distributed sets {} in {}".format( + self.k, + '(up to isomorphism)' if self.up_to_isom else '', + self.K) + + def cardinality(self): + r""" + Return the number of evenly distributed sets. + + Use with precaution as there can be a lot of such sets and this method + might be very long to answer! + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'),4) + sage: E + 4-evenly distributed sets (up to isomorphism) in Finite Field in a of size 5^2 + sage: E.cardinality() + 4 + + sage: E = EvenlyDistributedSetsBacktracker(GF(25,'a'), 4, up_to_isomorphism=False) + sage: E.cardinality() + 40 + """ + cdef n = 0 + self.count = 1 + for a in self: + n += a + self.count = 0 + return smallInteger(n) + + def _B_automorphisms(self): + r""" + Check whether B is minimal among its relabelization. + + This is an internal function and should only be call by the backtracker + implemented in the method `__iter__`. + + OUTPUT: + + - ``False`` if ``self.B`` is not minimal + + - ``True`` if ``self.B`` is minimal and ``self.up_to_isom = 1`` + + - the list of relabeled versions if ``self.B`` is minimal and ``self.up_to_isom = 0`` + + TESTS:: + + sage: from sage.combinat.designs.evenly_distributed_sets import \ + ....: EvenlyDistributedSetsBacktracker + sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=True) + sage: E.cardinality() # indirect doctest + 1 + sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=False) + sage: E.cardinality() # indirect doctest + 4 + """ + cdef unsigned int i,j,k,tmp1,tmp2,verify + cdef list B = [self.B[i] for i in range(1,self.k)] + B.append(self.q-1) + cdef list BB = [None]*self.k + cdef set relabs = set([tuple(B)]) + + # z -> (z - B[i]) / (B[j] - B[i]) + for i in range(self.k): + for j in range(self.k): + if i == j: + continue + tmp1 = self.diff[self.B[j]][self.B[i]] + + verify = 0 + for k in range(self.k): + if k == i: + BB[k] = self.q-1 + elif k == j: + BB[k] = 0 + else: + tmp2 = self.ratio[self.diff[self.B[k]][self.B[i]]][tmp1] + if tmp2 == 0 or tmp2 == self.q-1 or tmp2 < self.B[2]: + raise RuntimeError("there is a problem got tmp2={}".format(tmp2,self.B[2])) + elif tmp2 == self.B[2]: + verify = 1 + BB[k] = tmp2 + + if verify: + BB.sort() + if BB < B: + return False + + if not self.up_to_isom: + if not verify: + BB.sort() + if BB > B: + relabs.add(tuple(BB)) + + return sorted(relabs) + + @cython.cdivision(True) + @cython.boundscheck(False) + @cython.wraparound(False) + def __iter__(self): + r""" + Iterator through all evenly distributed sets that start with `[0,1]`. + + EXAMPLES:: + + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + + sage: E = EvenlyDistributedSetsBacktracker(Zmod(13),4) + sage: for B in E: + ....: print B + [0, 1, 11, 5] + """ + cdef unsigned int k = self.k + cdef unsigned int q = self.q + cdef unsigned int e = self.e + cdef unsigned int m = (q-1) / e + + # in the list B we store the candidate for being an e.d.s. + # we always have B[0] = 0 and B[1] = 1 + # because 0 is in B, the cosets of the elements of B must be + # disjoint. + cdef unsigned int kk = 2 + cdef unsigned int * B = self.B + B[0] = q-1 # the element 0 in K + B[1] = 0 # the element 1 in K + + memset(self.cosets, 0, e * sizeof(unsigned int)) + memset(self.t, 0, e * sizeof(unsigned int)) + + self.cosets[0] = 1 # the coset of 1 + + cdef unsigned int x = m + while True: + if self.check: + self._check(kk) + assert m < x < q-1, "got x < m or x > q where x={}".format(x) + + # try to append x + if self._add_element(x,kk): + # note: the element x is already added to B in ._add_element() + if kk == k-1: + ans = self._B_automorphisms() + if ans is False: + continue + elif self.count: + yield len(ans) + else: + for a in ans: + yield [self.list_K[q-1]] + [self.list_K[a[r]] for r in range(k-1)] + self._pop(kk) + else: + # we need to choose the next element from a new coset. In + # order to jump we artificially set x to the last element of + # the coset. + x += m - x%m - 1 + kk += 1 + + # now we determine the next element x to be tested + if x == q-2: + kk -= 1 + x = B[kk] + self._pop(kk) + if x == q-2: + kk -= 1 + x = B[kk] + self._pop(kk) + if x == q-2: + raise RuntimeError("this is impossible!") + + if kk == 1: + return + + x += 1 + + @cython.cdivision(True) + cdef inline int _add_element(self, unsigned int x, unsigned int kk) except -1: + r""" + Add the element ``x`` to ``B`` in position kk if the resulting set is + still evenly distributed. + """ + cdef unsigned int i,j + cdef unsigned int tmp + cdef unsigned int m = (self.q-1)/self.e + + # we check that we do not get a smaller evenly distributed set by a + # relabeling of the form + # 1. z -> (z - x) / (B[i] - x) that maps x -> 0 and B[i] -> 1 + # 2. z -> (z - B[i]) / (x - B[i]) that maps B[i] -> 0 and x -> 1 + if kk > 2: + for i in range(kk): + # isom of form 1 + tmp = self.diff[self.B[i]][x] + for j in range(kk): + if j == i: + continue + if self.ratio[tmp][self.diff[self.B[j]][x]] < self.B[2]: + return 0 + + # isom of form 2 + tmp = self.diff[x][self.B[i]] + for j in range(kk): + if j == i: + continue + if self.ratio[self.diff[self.B[j]][self.B[i]]][tmp] < self.B[2]: + return 0 + + for j in range(kk): + i = self.diff[x][self.B[j]] / m + if self.cosets[i] or self.t[i]: + memset(self.t, 0, self.e*sizeof(unsigned int)) + return 0 + self.t[i] = 1 + + self.B[kk] = x + for i in range(self.e): + if self.t[i]: + self.cosets[i] = 1 + self.t[i] = 0 + return 1 + + cdef inline void _pop(self, unsigned int kk): + r""" + Pop the element of ``self.B`` at position ``kk`` and updates + ``self.cosets`` + """ + cdef unsigned int i,j,x + cdef unsigned int m = (self.q-1)/self.e + x = self.B[kk] + for j in range(kk): + i = self.diff[x][self.B[j]] / m + self.cosets[i] = 0 + + cdef int _check(self, unsigned int kk) except -1: + r""" + Sanity check (only for debug purposes). + """ + cdef unsigned int i,j,x,y + cdef set s = set() + for i in range(kk): + x = self.B[i] + for j in range(i): + y = self.B[j] + s.add(self.diff_to_coset[x][y]) + + if set(j for j in range(self.e) if self.cosets[j]) != s: + raise RuntimeError("self.cosets is not synchronized with self.B!") From d3385807832a91a2a2171aeb9548059a672b5a59 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 22 Jan 2015 19:04:48 +0100 Subject: [PATCH 379/665] trac #17662: add module to the documentation --- src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/combinat/designs/__init__.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 66cb93a7d5f..4fe7bece9cf 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -85,6 +85,7 @@ Comprehensive Module list sage/combinat/designs/designs_pyx sage/combinat/designs/difference_family sage/combinat/designs/difference_matrices + sage/combinat/designs/evenly_distributed_sets sage/combinat/designs/ext_rep sage/combinat/designs/incidence_structures sage/combinat/designs/latin_squares diff --git a/src/sage/combinat/designs/__init__.py b/src/sage/combinat/designs/__init__.py index 8062201088b..58b3bb856d9 100644 --- a/src/sage/combinat/designs/__init__.py +++ b/src/sage/combinat/designs/__init__.py @@ -32,4 +32,5 @@ - :ref:`sage.combinat.designs.ext_rep` - :ref:`sage.combinat.designs.designs_pyx` - :ref:`sage.combinat.designs.subhypergraph_search` +- :ref:`sage.combinat.designs.evenly_distributed_sets` """ From 27c586dd6b4b05cefd80cb5ffbfc145a3b565541 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Sun, 19 Apr 2015 17:38:01 +0200 Subject: [PATCH 380/665] partial review; ensure that labelled trees get normalized correctly if their children have equal shapes --- src/sage/combinat/ordered_tree.py | 78 ++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index cba226ba6e3..d358beff776 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -526,12 +526,22 @@ def left_right_symmetry(self): def sort_key(self): """ - Return a tuple of numbers that can be used to sort the trees. + Return a tuple of nonnegative integers encoding the tree + ``self``. - This tuple is in fact an encoding of the tree. The values are - the valences of the vertices. The first value is the valence of the - root. Then the rest of the tuple is the concatenation of the tuples - associated to subtrees from left to right. + The first entry of the tuple is the number of children of the + root. Then the rest of the tuple is the concatenation of the + tuples associated to subtrees from left to right. + + This tuple characterizes the tree uniquely, and can be used to + sort the ordered trees. + + .. NOTE:: + + On the :class:`LabelledOrderedTree` subclass, this method + is overridden by a slightly different method, which encodes + not only the numbers of children of the nodes of ``self``, + but also their labels. EXAMPLES:: @@ -1101,7 +1111,7 @@ class LabelledOrderedTree(AbstractLabelledClonableTree, OrderedTree): - ``children`` -- a list or tuple or more generally any iterable of trees or object convertible to trees - - ``label`` -- any Sage object default to ``None`` + - ``label`` -- any Sage object (default: ``None``) EXAMPLES:: @@ -1153,6 +1163,62 @@ def _auto_parent(cls): _UnLabelled = OrderedTree + @combinatorial_map(order=2, name="Left-right symmetry") + def left_right_symmetry(self): + r""" + Return the symmetric tree of ``self`` + + EXAMPLES:: + + sage: L2 = LabelledOrderedTree([], label=2) + sage: L3 = LabelledOrderedTree([], label=3) + sage: T23 = LabelledOrderedTree([L2, L3], label=4) + sage: T23.left_right_symmetry() + 4[3[], 2[]] + sage: T223 = LabelledOrderedTree([L2, T23], label=17) + sage: T223.left_right_symmetry() + 17[4[3[], 2[]], 2[]] + sage: T223.left_right_symmetry().left_right_symmetry() == T223 + True + """ + children = [c.left_right_symmetry() for c in self] + children.reverse() + return LabelledOrderedTree(children, label=self.label()) + + def sort_key(self): + """ + Return a tuple of nonnegative integers encoding the labelled + tree ``self``. + + The first entry of the tuple is a pair consisting of the + number of children of the root and the label of the root. Then + the rest of the tuple is the concatenation of the tuples + associated to subtrees from left to right. + + This tuple characterizes the labelled tree uniquely, and can + be used to sort the labelled ordered trees provided that the + labels belong to a type which is totally ordered. + + EXAMPLES:: + + sage: L2 = LabelledOrderedTree([], label=2) + sage: L3 = LabelledOrderedTree([], label=3) + sage: T23 = LabelledOrderedTree([L2, L3], label=4) + sage: T23.sort_key() + ((2, 4), (0, 2), (0, 3)) + sage: T32 = LabelledOrderedTree([L3, L2], label=5) + sage: T32.sort_key() + ((2, 5), (0, 3), (0, 2)) + sage: T23322 = LabelledOrderedTree([T23, T32, L2], label=14) + sage: T23322.sort_key() + ((3, 14), (2, 4), (0, 2), (0, 3), (2, 5), (0, 3), (0, 2), (0, 2)) + """ + l = len(self) + if l == 0: + return ((0, self.label()),) + resu = [(l, self.label())] + [u for t in self for u in t.sort_key()] + return tuple(resu) + class LabelledOrderedTrees(UniqueRepresentation, Parent): """ From 6e9cf9e72ced0969fd920eca5437f2e3c1d33009 Mon Sep 17 00:00:00 2001 From: Christian Nassau Date: Sun, 19 Apr 2015 18:49:07 +0200 Subject: [PATCH 381/665] Ticket 16836 fix __neg__ for cartesian products --- src/sage/categories/additive_magmas.py | 83 +++++++++----------------- 1 file changed, 29 insertions(+), 54 deletions(-) diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index 4ffbe1d7c81..d51eaea7924 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -855,6 +855,15 @@ def __neg__(self): 'sage.categories.additive_magmas' sage: b._neg_.__module__ 'sage.combinat.free_module' + sage: F = CombinatorialFreeModule(ZZ, ['a','b']) + sage: a,b = F.gens() + sage: FF = cartesian_product((F,F)) + sage: x = cartesian_product([a,2*a-3*b]) ; x + B[(0, 'a')] + 2*B[(1, 'a')] - 3*B[(1, 'b')] + sage: x.parent() is FF + True + sage: -x + -B[(0, 'a')] - 2*B[(1, 'a')] + 3*B[(1, 'b')] """ return self._neg_() @@ -916,6 +925,26 @@ def extra_super_categories(self): """ return [AdditiveMagmas().AdditiveUnital().AdditiveInverse()] + class ElementMethods: + def __neg__(self): + """ + Return the negation of ``self``. + + EXAMPLES:: + + sage: x = cartesian_product((GF(7)(2),17)) ; x + (2, 17) + sage: -x + (5, -17) + + TESTS:: + + sage: x.parent() in AdditiveMagmas().AdditiveUnital().AdditiveInverse().CartesianProducts() + True + """ + return self.parent()._cartesian_product_of_elements( + [-x for x in self.cartesian_factors()]) + class CartesianProducts(CartesianProductsCategory): def extra_super_categories(self): """ @@ -945,60 +974,6 @@ def zero(self): return self._cartesian_product_of_elements( _.zero() for _ in self.cartesian_factors()) - class ElementMethods: - def __neg__(self): - r""" - Return the negation of ``self``, if it exists. - - The inverse is computed by negating each cartesian - factor and attempting to convert the result back - to the original parent. - - For example, if one of the cartesian factor is an - element ``x`` of `\NN`, the result of ``-x`` is in - `\ZZ`. So we need to convert it back to `\NN`. As - a side effect, this checks that ``x`` indeed has a - negation in `\NN`. - - If needed an optimized version without this - conversion could be implemented in - :class:`AdditiveMagmas.AdditiveUnital.AdditiveInverse.ElementMethods`. - - EXAMPLES:: - - sage: G=GF(5); GG = G.cartesian_product(G) - sage: oneone = GG([GF(5)(1),GF(5)(1)]) - sage: -oneone - (4, 4) - - sage: NNSemiring = NonNegativeIntegers(category=Semirings() & InfiniteEnumeratedSets()) - sage: C = cartesian_product([ZZ,NNSemiring,RR]) - sage: -C([2,0,.4]) - (-2, 0, -0.400000000000000) - - sage: c = C.an_element(); c - (1, 42, 1.00000000000000) - sage: -c - Traceback (most recent call last): - ... - ValueError: Value -42 in not in Non negative integers. - - .. TODO:: - - Use plain ``NN`` above once it is a semiring. - See :trac:`16406`. There is a further issue - with ``NN`` being lazy imported which breaks - the assertion that the inputs are parents in - ``cartesian_product``:: - - sage: cartesian_product([ZZ, NN, RR]) - Traceback (most recent call last): - ... - AssertionError - """ - return self.parent()( - -x for x in self.cartesian_factors()) - class Algebras(AlgebrasCategory): def extra_super_categories(self): From a70a5314dbc203c66a08f1f070b739112921a146 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Sun, 19 Apr 2015 13:14:39 -0400 Subject: [PATCH 382/665] corrections to references and documentation --- src/sage/combinat/sf/macdonald.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 336c8c55ba1..f6e296d17d6 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -675,13 +675,15 @@ def cmunu1(mu, nu): def cmunu(mu, nu): r""" Return the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu`. - A theorem of F. Bergeron, A. Garsia and M. Haiman [BH2013]_ states + Proposition 5 of F. Bergeron and M. Haiman [BH2013]_ states .. MATH:: c_{\mu\nu} = \sum_{\alpha \leftarrow \nu} c_{\mu\alpha} c_{\alpha\nu} B_{\alpha/\nu}/B_{\mu/\nu} - where `c_{\mu\nu}` is the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu`. + where `c_{\mu\nu}` is the coefficient of `{\tilde H}_\nu` in + `h_r^\perp {\tilde H}_\mu` and `B_{\mu/\nu}` is the bi-exponent generator + implemented in the function :func:`sage.combinat.sf.macdonald.Bmu`. INPUT: @@ -1303,8 +1305,8 @@ def __init__(self, macdonald): K_{\lambda\mu}(q,t^{-1}) s_\lambda` where `K_{\lambda\mu}(q,t)` are the Macdonald `(q,t)`-Kostka coefficients and `n(\mu) = \sum_{i} (i-1) \mu_i`. - It is implemented here by using a Pieri formula due to F. Bergeron, - A. Garsia and M. Haiman [BH2013]_. + It is implemented here by using a Pieri formula due to F. Bergeron + and M. Haiman [BH2013]_. INPUT: @@ -1340,8 +1342,9 @@ def _Lmunu(self, nu, mu ): where the sum is over partitions `\gamma \subseteq \mu` with `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. There is a recursive - formula for `c_{\mu\gamma}` which is due to F. Bergeron, A. Garsia, and M. - Haiman [BH2013]_. + formula for `c_{\mu\gamma}` which is due to F. Bergeron and M. + Haiman [BH2013]_ and this is implemented in + :func:`sage.combinat.sf.macdonald.cmunu`. INPUT: From 5cfb178721813a2260a5177a9a731e9119033253 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Sun, 19 Apr 2015 12:11:54 +0200 Subject: [PATCH 383/665] 16659: Lift_idempotent now work, more test with 0-Hecke, TODO: explanation algorithms --- .../finite_dimensional_algebras_with_basis.py | 76 +++++++++++++++---- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 648d8ee2d98..6688954364e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -174,8 +174,7 @@ def radical_basis(self, cache_products=True): for i in keys for j,c in product_on_basis(y,i)} for y in keys] - mat = [ - [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) + mat = [ [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) for x in cache] for y in cache] @@ -432,6 +431,7 @@ def central_orthogonal_idempotents(self): EXAMPLES:: + sage: import itertools sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y @@ -442,23 +442,48 @@ def central_orthogonal_idempotents(self): An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) - sage: A.central_orthogonal_idempotents() - [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] - + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], - 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - - 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - + sage: orth = A.central_orthogonal_idempotents(); orth + [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] + - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/2*B[9] - 1/2*B[3], B[0], + -B[0] + 1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/4*B[5] - 1/4*B[7] + + 1/4*B[11], -B[0] + 1/2*B[9] + 1/2*B[3], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] + sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) + True + + We construct the minimum orthogonal idempotents of the `0`-Hecke + monoid algebra:: + + sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup + sage: W = WeylGroup(['A', 3]); W.rename("W") + sage: ambient_monoid = FiniteSetMaps(W, action="right") + sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) + sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()); M + A submonoid of (Maps from W to itself) with 3 generators + sage: A = M.algebra(QQ) + sage: orth = A.central_orthogonal_idempotents() + sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) + True + + TODO: More documentation, explanation algorithm, merge with + _lift_idempotent ? """ Aquo = self.semisimple_quotient() - orth_quo = Aquo.central_orthogonal_idempotents() - return [self._lift_idempotent(x) for x in orth_quo] + orths = [self._lift_idempotent(x) for x in Aquo.central_orthogonal_idempotents()] + # Construction of the orthogonal idempotents + idems = [] + one = self.one() + for g in orths: + f = sum(idems) # 0 if idems is empty + idems.append((one - f) * g * (one - f)) + return idems def _lift_idempotent(self, x): r""" - Lift a central orthogonal idempotent of the semisimple quotient of - ``self`` into a central orthogonal idempotent of ``self``. + Lift an idempotent of the semisimple quotient of ``self`` into an + idempotent of ``self``. ALGORITHM: @@ -484,16 +509,18 @@ def _lift_idempotent(self, x): algebras." Pure and Applied Mathematics, Vol. XI Interscience Publishers, a division of John Wiley & Sons, New York-London 1962 - pp 545--556 + pp 545--546 + + TODO: merge in central_orthogonal_idempotents? """ idempOld = None assert x in self.semisimple_quotient() assert (x == x*x), "Element is not an idempotent" idemp = x.lift() - p = idemp.parent() + one = idemp.parent().one() while idemp != idempOld: tmp = idemp - idemp = (p.one() - (p.one() - idemp**2)**2) + idemp = (one - (one - idemp**2)**2) idempOld = tmp return idemp @@ -525,6 +552,25 @@ def cartan_invariants_matrix(self, side='left'): [0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 2 0] [0 0 0 0 0 0 0 0 2] + + With the 0-Hecke monoid algebra:: + + sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup + sage: W = WeylGroup(['A', 3]); W.rename("W") + sage: ambient_monoid = FiniteSetMaps(W, action="right") + sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) + sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()); M + A submonoid of (Maps from W to itself) with 3 generators + sage: A = M.algebra(QQ) + sage: A.cartan_invariants_matrix() + [1 0 0 0 0 0 0 0] + [0 1 1 1 0 0 0 0] + [0 1 1 1 0 0 0 0] + [0 1 1 2 0 1 0 0] + [0 0 0 0 1 1 1 0] + [0 0 0 1 1 2 1 0] + [0 0 0 0 1 1 1 0] + [0 0 0 0 0 0 0 1] """ Aquo = self.semisimple_quotient() orth_quo = Aquo.central_orthogonal_idempotents() From b0ac2e27ee00718c0fabe164aab4bdd096a5d9a9 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sun, 19 Apr 2015 14:23:43 -0700 Subject: [PATCH 384/665] remove now unnecessary call to self.string --- .../root_system/integrable_representations.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index c5220907d53..514520e71c5 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -12,7 +12,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.category_object import CategoryObject -#from sage.structure.parent import Parent from sage.categories.modules import Modules from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.root_space import RootSpace @@ -629,10 +628,13 @@ def dominant_maximal(self): """ A weight `\\mu` is *maximal* if it has nonzero multiplicity but `\\mu+\\delta`` has multiplicity zero. There are a finite number - of dominant maximal weights. + of dominant maximal weights. Indeed, [Kac] Proposition 12.6 + shows that the dominant maximal weights are in bijection with + the classical weights in `k\cdot F` where `F` is the fundamental + alcove and `k` is the level. The construction used in this + method is based on that Proposition. - This function will replace dominant maximal after it has been - fully tested. + """ k = self.level() @@ -688,9 +690,6 @@ def strings(self, depth=12): 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ - # FIXME: This call to string should not be necessary as it is - # highly redundant to generate the data for dominant_maximal - self.string(self._Lam, depth) for max_weight in self.dominant_maximal(): s = self.string(max_weight, depth) print "%s:"%max_weight, From 8f6a8670d2708b960a9f89490a59c76b9099d451 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Sun, 19 Apr 2015 23:30:22 +0200 Subject: [PATCH 385/665] 16659: cleaning lifting, work for real now --- .../finite_dimensional_algebras_with_basis.py | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6688954364e..6d2f847ae71 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -429,6 +429,15 @@ def central_orthogonal_idempotents(self): - ``self`` -- a finite dimensional algebra + ALGORITHM: + + Let '\overline{e}' be a central orthogonal idempotent of the + semisimple quotient `\overline{A}` of a finite dimensional algebra + `A`. Let `e \in A` such that the projection of `e` in + `\overline{A}` is `\overline{e}`. We iterate the formula + `1 - (1 - e^2)^2` until having an idempotent. See [CR62] for + correctness and termination proofs. + EXAMPLES:: sage: import itertools @@ -445,9 +454,9 @@ def central_orthogonal_idempotents(self): sage: orth = A.central_orthogonal_idempotents(); orth [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], 1/2*B[9] - 1/2*B[3], B[0], - -B[0] + 1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/4*B[5] - 1/4*B[7] + - 1/4*B[11], -B[0] + 1/2*B[9] + 1/2*B[3], B[0] + 1/4*B[1] - + - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], + -B[0] + 1/2*B[4] + 1/2*B[8], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - + 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) @@ -467,40 +476,6 @@ def central_orthogonal_idempotents(self): sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) True - TODO: More documentation, explanation algorithm, merge with - _lift_idempotent ? - """ - Aquo = self.semisimple_quotient() - orths = [self._lift_idempotent(x) for x in Aquo.central_orthogonal_idempotents()] - # Construction of the orthogonal idempotents - idems = [] - one = self.one() - for g in orths: - f = sum(idems) # 0 if idems is empty - idems.append((one - f) * g * (one - f)) - return idems - - def _lift_idempotent(self, x): - r""" - Lift an idempotent of the semisimple quotient of ``self`` into an - idempotent of ``self``. - - ALGORITHM: - - Let '\overline{e}' be a central orthogonal idempotent of the - semisimple quotient `\overline{A}` of a finite dimensional algebra - `A`. Let `e \in A` such that the projection of `e` in - `\overline{A}` is `\overline{e}`. We iterate the formula - `1 - (1 - e^2)^2` until having an idempotent. See [CR62] for - correctness and termination proofs. - - EXAMPLES:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: Aquo = A.semisimple_quotient() - sage: orth = Aquo.central_orthogonal_idempotents() - sage: A._lift_idempotent(orth[1]) - x REFERENCES: @@ -511,18 +486,24 @@ def _lift_idempotent(self, x): division of John Wiley & Sons, New York-London 1962 pp 545--546 - TODO: merge in central_orthogonal_idempotents? + TODO: More documentation, explanation algorithm """ - idempOld = None - assert x in self.semisimple_quotient() - assert (x == x*x), "Element is not an idempotent" - idemp = x.lift() - one = idemp.parent().one() - while idemp != idempOld: - tmp = idemp - idemp = (one - (one - idemp**2)**2) - idempOld = tmp - return idemp + def lift(idemp, one): + idempOld = None + while idemp != idempOld: + tmp = idemp + idemp = (one - (one - idemp**2)**2) + idempOld = tmp + return idemp + Aquo = self.semisimple_quotient() + one = self.one() + orths = [lift(x.lift(), one) for x in Aquo.central_orthogonal_idempotents()] + # Construction of the orthogonal idempotents + idems = [] + for g in orths: + f = sum(idems) # 0 if idems is empty + idems.append(lift((one - f) * g * (one - f), one)) + return idems @cached_method def cartan_invariants_matrix(self, side='left'): @@ -577,7 +558,8 @@ def cartan_invariants_matrix(self, side='left'): # Dimension of simple modules dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] - orth = [self._lift_idempotent(x) for x in orth_quo] + # Orthogonal idempotents + orth = self.central_orthogonal_idempotents() return Matrix(self.base_ring(), len(orth), lambda i,j: self.pierce_decomposition_component(orth[i], From a3708f0e9ff05a72155ab873de00acf41ce69f45 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 19 Apr 2015 17:52:33 -0400 Subject: [PATCH 386/665] #18252 Trivial fix to graph documentation --- src/sage/graphs/generic_graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f06fd429f7d..f7d2e7a20aa 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -13932,7 +13932,7 @@ def add_cycle(self, vertices): def add_path(self, vertices): """ - Adds a cycle to the graph with the given vertices. If the vertices + Adds a path to the graph with the given vertices. If the vertices are already present, only the edges are added. For digraphs, adds the directed path vertices[0], ..., @@ -13942,7 +13942,7 @@ def add_path(self, vertices): - ``vertices`` - a list of indices for the vertices of - the cycle to be added. + the path to be added. EXAMPLES:: From 9196d339a8adafb0c011d0f0ddb4172fbcbdd136 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 19 Apr 2015 23:48:53 -0700 Subject: [PATCH 387/665] Some cleanup of the docstrings and line lengths. --- src/sage/combinat/sf/macdonald.py | 191 ++++++++++++++++-------------- 1 file changed, 104 insertions(+), 87 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index fe867e3afe3..369293a0eed 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -52,9 +52,10 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom +from sage.categories.modules_with_basis import ModulesWithBasis import sfa -import sage.combinat.partition -from sage.combinat.partition import Partition +from sage.combinat.partition import Partition, Partitions +from sage.combinat.skew_partition import SkewPartition from sage.matrix.all import MatrixSpace from sage.rings.all import QQ from sage.misc.all import prod @@ -608,13 +609,13 @@ def c2(part, q, t): return res @cached_function -def Bmu( mu ): +def Bmu(mu): r""" - Returns the bi-exponent generator for the cells of ``mu``. - + Return the bi-exponent generator for the cells of ``mu``. + The weight in the bi-exponent generator is `t` raised the `x`-coordinate of the cell, `q` raised to the `y` coordinate. - + INPUT: - ``mu`` -- a partition or a skew partition @@ -632,7 +633,7 @@ def Bmu( mu ): q^2*t + q^2 + q*t + t """ q,t = QQqt.gens() - return sum(t**c[0]*q**c[1] for c in mu.cells()) + return QQqt.sum(t**c[0] * q**c[1] for c in mu.cells()) @cached_function def cmunu1(mu, nu): @@ -657,26 +658,35 @@ def cmunu1(mu, nu): sage: Sym = SymmetricFunctions(QQ['q','t'].fraction_field()) sage: h = Sym.h() sage: Ht = Sym.macdonald().Ht() - sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) == cmunu1(Partition([3,2,1]),nu) for nu in Partition([3,2,1]).down_list()) + sage: all(Ht[3,2,1].skew_by(h[1]).coefficient(nu) + ....: == cmunu1(Partition([3,2,1]),nu) + ....: for nu in Partition([3,2,1]).down_list()) True """ q,t = QQqt.gens() - c = sage.combinat.skew_partition.SkewPartition([mu,nu]).cells()[0] - A = prod((t**mu.leg_length(*s)-q**(mu.arm_length(*s)+1))/(t**nu.leg_length(*s)-q**(nu.arm_length(*s)+1)) for s in nu.cells() if s[0]==c[0]) - B = prod((q**mu.arm_length(*s)-t**(mu.leg_length(*s)+1))/(q**nu.arm_length(*s)-t**(nu.leg_length(*s)+1)) for s in nu.cells() if s[1]==c[1]) + from sage.combinat.skew_partition import SkewPartition + c = SkewPartition([mu,nu]).cells()[0] + A = prod((t**mu.leg_length(*s) - q**(mu.arm_length(*s)+1)) + / (t**nu.leg_length(*s) - q**(nu.arm_length(*s)+1)) + for s in nu.cells() if s[0] == c[0]) + B = prod((q**mu.arm_length(*s) - t**(mu.leg_length(*s)+1)) + / (q**nu.arm_length(*s) - t**(nu.leg_length(*s)+1)) + for s in nu.cells() if s[1] == c[1]) return A*B - + @cached_function def cmunu(mu, nu): r""" Return the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu`. + Proposition 5 of F. Bergeron and M. Haiman [BH2013]_ states .. MATH:: - c_{\mu\nu} = \sum_{\alpha \leftarrow \nu} c_{\mu\alpha} c_{\alpha\nu} B_{\alpha/\nu}/B_{\mu/\nu} - - where `c_{\mu\nu}` is the coefficient of `{\tilde H}_\nu` in + c_{\mu\nu} = \sum_{\alpha \leftarrow \nu} c_{\mu\alpha} + c_{\alpha\nu} B_{\alpha/\nu}/B_{\mu/\nu} + + where `c_{\mu\nu}` is the coefficient of `{\tilde H}_\nu` in `h_r^\perp {\tilde H}_\mu` and `B_{\mu/\nu}` is the bi-exponent generator implemented in the function :func:`sage.combinat.sf.macdonald.Bmu`. @@ -698,16 +708,20 @@ def cmunu(mu, nu): sage: Sym = SymmetricFunctions(QQ['q','t'].fraction_field()) sage: h = Sym.h() sage: Ht = Sym.macdonald().Ht() - sage: all(Ht[2,2].skew_by(h[r]).coefficient(nu) == cmunu(Partition([2,2]),nu) for r in range(1,5) for nu in Partitions(4-r)) + sage: all(Ht[2,2].skew_by(h[r]).coefficient(nu) + ....: == cmunu(Partition([2,2]),nu) + ....: for r in range(1,5) for nu in Partitions(4-r)) True """ - if nu==[]: + if not nu: return 1 if not mu.contains(nu): return 0 - if mu.size()==nu.size()+1: + if mu.size() == nu.size() + 1: return cmunu1(mu, nu) - return sum(cmunu(mu, al)*cmunu1(al, nu)*Bmu(sage.combinat.skew_partition.SkewPartition([al,nu])) for al in nu.up_list())/Bmu(sage.combinat.skew_partition.SkewPartition([mu,nu])) + num = sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu(SkewPartition([al,nu])) + for al in nu.up_list()) + return num / Bmu(SkewPartition([mu,nu])) #Generic MacdonaldPolynomials class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): @@ -752,7 +766,7 @@ def __init__(self, macdonald): # common category BasesByOrthotriangularity (shared with Jack, HL, orthotriang, Mcdo) if hasattr(self, "_s_cache"): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) - category = sage.categories.all.ModulesWithBasis(self.base_ring()) + category = ModulesWithBasis(self.base_ring()) self .register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) @@ -996,7 +1010,7 @@ def __init__(self, macdonald): self._J = macdonald.J() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) - category = sage.categories.all.ModulesWithBasis(self.base_ring()) + category = ModulesWithBasis(self.base_ring()) phi = self._J.module_morphism(diagonal = self.c2, codomain = self, category = category) self.register_coercion( phi) self._J.register_coercion(~phi) @@ -1067,7 +1081,7 @@ def __init__(self, macdonald): self._P = macdonald.P() # temporary until Hom(GradedHopfAlgebrasWithBasis) works better - category = sage.categories.all.ModulesWithBasis(self.base_ring()) + category = ModulesWithBasis(self.base_ring()) phi = self._P.module_morphism(diagonal = self._P.scalar_qt_basis, codomain = self, category = category) self .register_coercion( phi) self._P.register_coercion(~phi) @@ -1196,14 +1210,13 @@ def __init__(self, macdonald): MacdonaldPolynomials_generic.__init__(self, macdonald) self._m = self._sym.m() self._Lmunu = macdonald.Ht()._Lmunu - category = sage.categories.all.ModulesWithBasis(self.base_ring()) + category = ModulesWithBasis(self.base_ring()) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) - def _self_to_m( self, x ): + def _self_to_m(self, x): r""" - Takes an element of the ``H`` basis and returns the expansion in the - monomial basis. + Return an element ``x`` of ``self`` expanded in the monomial basis. INPUT: @@ -1227,26 +1240,26 @@ def _self_to_m( self, x ): sage: m = Sym.m() sage: m(H[2,1]) ((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3] - """ - return self._m._from_dict({ part2: - self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=1/self.t)*self.t**mu.weighted_size() - for mu in x.homogeneous_component(d).support())) - for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) + return self._m._from_dict({ part2: + self._base(sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=1/self.t) + * self.t**mu.weighted_size() + for mu in x.homogeneous_component(d).support())) + for d in range(x.degree()+1) for part2 in Partitions(d) }) def _m_to_self( self, f ): r""" Convert an element ``f`` from the monomial basis to the ``H`` basis. This calculation is performed by using the fact that `H_\mu[X(1-t)]` - is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading - coefficient of the expansion of ``f`` in the `H_\mu` basis is equal to - the leading coefficient of `c_\mu^{-1} f[X(1-t)]`. - - If `t=1`, we must appeal to another triangularity since ``Ht`` is (usually) - still a basis, however `H_\mu[X(1-t)]=0`. In this case we assume that - it is a basis and `H_\mu[X(q-1)]` is `c_\mu m_{\mu'}` plus terms which - are lower in dominance order. + is `c_\mu m_\mu` plus terms which are smaller in dominance order. + The leading coefficient of the expansion of ``f`` in the `H_\mu` + basis is equal to the leading coefficient of `c_\mu^{-1} f[X(1-t)]`. + + If `t=1`, we must appeal to another triangularity since ``Ht`` + is (usually) still a basis, however `H_\mu[X(1-t)]=0`. In this + case we assume that it is a basis and `H_\mu[X(q-1)]` is + `c_\mu m_{\mu'}` plus terms which are lower in dominance order. INPUT: @@ -1273,21 +1286,20 @@ def _m_to_self( self, f ): sage: m = Sym.m() sage: H((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) McdH[2, 1] - """ - if self.t==1: - subsval = 1/self.q + if self.t == 1: + subsval = 1 / self.q fl = lambda x: x.conjugate() else: subsval = self.t fl = lambda x: x - g = f.theta_qt(q=subsval,t=0) + g = f.theta_qt(q=subsval, t=0) out = {} while not g.is_zero(): sprt = g.support() - Hmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval,t=0) - out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1])/Hmu.coefficient(sprt[-1])) - g -= out[fl(sprt[-1])]*Hmu + Hmu = self._self_to_m( self(fl(sprt[-1])) ).theta_qt(q=subsval, t=0) + out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1]) / Hmu.coefficient(sprt[-1])) + g -= out[fl(sprt[-1])] * Hmu return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): @@ -1319,7 +1331,7 @@ def __init__(self, macdonald): MacdonaldPolynomials_generic.__init__(self, macdonald) self._self_to_m_cache = _ht_to_m_cache self._m = self._sym.m() - category = sage.categories.all.ModulesWithBasis(self.base_ring()) + category = ModulesWithBasis(self.base_ring()) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) @@ -1327,18 +1339,19 @@ def _Lmunu(self, nu, mu ): r""" Return the coefficient of `m_\nu` in `{\tilde H}_\mu`. - The coefficient is a `(q,t)`-analogue of `n` choose `\nu`. Let `c_{\mu\gamma}` - be the coefficient of `{\tilde H}_\gamma` in `h_r^\perp {\tilde H}_\mu`. The - coefficient of `m_\nu` in `{\tilde H}_\mu` is + The coefficient is a `(q,t)`-analogue of `n` choose `\nu`. Let + `c_{\mu\gamma}` be the coefficient of `{\tilde H}_\gamma` in + `h_r^\perp {\tilde H}_\mu`. The coefficient of `m_\nu` in + `{\tilde H}_\mu` is .. MATH:: - L_{\mu\nu} = \sum_{\gamma} c_{\mu\gamma} L_{\gamma\overline{\nu}} + L_{\mu\nu} = \sum_{\gamma} c_{\mu\gamma} L_{\gamma\overline{\nu}}, - where the sum is over partitions `\gamma \subseteq \mu` with - `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. There is a recursive - formula for `c_{\mu\gamma}` which is due to F. Bergeron and M. - Haiman [BH2013]_ and this is implemented in + where the sum is over partitions `\gamma \subseteq \mu` with + `\gamma \vdash |(\nu_1, \ldots, \nu_{\ell(\nu)-1})|`. There is a + recursive formula for `c_{\mu\gamma}` which is due to F. Bergeron + and M. Haiman [BH2013]_ and this is implemented in :func:`sage.combinat.sf.macdonald.cmunu`. INPUT: @@ -1362,20 +1375,21 @@ def _Lmunu(self, nu, mu ): q*t + 2*t^2 + q + t + 1 """ - if len(mu)==0: - if len(nu)==0: + if not mu: + if not nu: return 1 else: return 0 if (mu,nu) in self._self_to_m_cache: return self._self_to_m_cache[(mu,nu)] - if len(nu)==1: + if len(nu) == 1: return 1 - if nu[-1]==1: - self._self_to_m_cache[(mu,nu)] = QQqt(sum(cmunu1(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) for ga in mu.down_list())) + if nu[-1] == 1: + self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu1(mu,ga) * self._Lmunu(Partition(nu[:-1]), ga) + for ga in mu.down_list()) ) return self._self_to_m_cache[(mu,nu)] - self._self_to_m_cache[(mu,nu)] = QQqt(sum( cmunu(mu,ga)*self._Lmunu(Partition(nu[:-1]), ga) - for ga in sage.combinat.partition.Partitions(nu.size()-nu[-1]) if mu.contains(ga))) + self._self_to_m_cache[(mu,nu)] = QQqt(sum( cmunu(mu,ga) * self._Lmunu(Partition(nu[:-1]), ga) + for ga in Partitions(nu.size()-nu[-1]) if mu.contains(ga) )) return self._self_to_m_cache[(mu,nu)] def _self_to_m(self, x): @@ -1407,24 +1421,25 @@ def _self_to_m(self, x): ((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3] """ - return self._m._from_dict({ part2: - self._base(sum(x.coefficient(mu)*QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=self.t) - for mu in x.homogeneous_component(d).support())) - for d in range(x.degree()+1) for part2 in sage.combinat.partition.Partitions(d)}) + return self._m._from_dict({ part2: + self._base( sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) + for mu in x.homogeneous_component(d).support()) ) + for d in range(x.degree()+1) for part2 in Partitions(d) }) def _m_to_self( self, f ): r""" Convert an element ``f`` from the monomial basis to the ``Ht`` basis. - This calculation is performed by using the fact that `{\tilde H}_\mu[X(t-1)]` - is `c_\mu m_\mu` plus terms which are smaller in dominance order. The leading - coefficient of the expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to + This calculation is performed by using the fact that + `{\tilde H}_\mu[X(t-1)]` is `c_\mu m_\mu` plus terms which are + smaller in dominance order. The leading coefficient of the + expansion of ``f`` in the `{\tilde H}_\mu` basis is equal to the leading coefficient of `c_\mu^{-1} f[X(t-1)]`. - - If `t=1`, we must appeal to another triangularity since ``Ht`` is (usually) - still a basis, however `{\tilde H}_\mu[X(t-1)]=0`. In this case we assume that - it is a basis and `{\tilde H}_\mu[X(q-1)]` is `c_\mu m_{\mu'}` plus terms which - are lower in dominance order. + + If `t=1`, we must appeal to another triangularity since ``Ht`` + is (usually) still a basis, however `{\tilde H}_\mu[X(t-1)]=0`. + In this case we assume that it is a basis and `{\tilde H}_\mu[X(q-1)]` + is `c_\mu m_{\mu'}` plus terms which are lower in dominance order. INPUT: @@ -1451,21 +1466,21 @@ def _m_to_self( self, f ): sage: m = Sym.m() sage: Ht((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) McdHt[2, 1] - + """ - if self.t==1: - subsval = 1/self.q + if self.t == 1: + subsval = ~self.q fl = lambda x: x.conjugate() else: - subsval = 1/self.t + subsval = ~self.t fl = lambda x: x - g = f.theta_qt(q=subsval,t=0) + g = f.theta_qt(q=subsval, t=0) out = {} while not g.is_zero(): sprt = g.support() - Htmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval,t=0) - out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1])/Htmu.coefficient(sprt[-1])) - g -= out[fl(sprt[-1])]*Htmu + Htmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval, t=0) + out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1]) / Htmu.coefficient(sprt[-1])) + g -= out[fl(sprt[-1])] * Htmu return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): @@ -1682,7 +1697,8 @@ def _creation_by_determinant_helper(self, k, part): (q^3*t-q^2*t-q+1)*McdS[2, 1] + (q^3-q^2*t-q+t)*McdS[3] """ (q,t) = QQqt.gens() - S = sage.combinat.sf.sf.SymmetricFunctions(QQqt).macdonald().S() + from sage.combinat.sf.sf import SymmetricFunctions + S = SymmetricFunctions(QQqt).macdonald().S() part += [0]*(k-len(part)) @@ -1833,8 +1849,8 @@ def qt_kostka(lam, mu): sage: qt_kostka([2,1],[1,1,1,1]) 0 """ - lam = sage.combinat.partition.Partition(lam) - mu = sage.combinat.partition.Partition(mu) + lam = Partition(lam) + mu = Partition(mu) if lam.size() != mu.size(): return QQqt.zero() @@ -1842,11 +1858,12 @@ def qt_kostka(lam, mu): if (lam,mu) in _qt_kostka_cache: return _qt_kostka_cache[(lam,mu)] - Sym = sage.combinat.sf.sf.SymmetricFunctions(QQqt) + from sage.combinat.sf.sf import SymmetricFunctions + Sym = SymmetricFunctions(QQqt) H = Sym.macdonald().H() s = Sym.schur() - parts = sage.combinat.partition.Partitions(mu.size()) + parts = Partitions(mu.size()) for p2 in parts: res = s(H(p2)) From 59cb8d2ec7ee3710bf0c7b3e2948382279fa7469 Mon Sep 17 00:00:00 2001 From: Benjamin Hackl Date: Mon, 20 Apr 2015 10:19:40 +0200 Subject: [PATCH 388/665] TESTS:: --> TESTS: --- src/sage/combinat/dyck_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index ff49b77f0c0..511cacc1ec7 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -3503,7 +3503,7 @@ class DyckWords_size(DyckWords): """ def __init__(self, k1, k2): r""" - TESTS:: + TESTS: Check that :trac:`18244` is fixed:: From b73cd8b97cc96c2c4373c91633aeed7ba7f8d9de Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 20 Apr 2015 10:23:43 +0200 Subject: [PATCH 389/665] Trac 9787: add doctest --- src/sage/rings/polynomial/polynomial_ring.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index d4ddcf89193..39b71efb7e6 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1800,6 +1800,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r correctly (see :trac:`9787`):: sage: R. = GF(101)[] + sage: R.lagrange_polynomial([[1, 0], [2, 0]]) + 0 sage: R.lagrange_polynomial([[1, 0], [2, 0], [3, 0]]) 0 From 87eea8dce29ccb3e8eda0d35e982ac4352aa5179 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 12:11:34 +0200 Subject: [PATCH 390/665] trac #17662: review --- .../designs/evenly_distributed_sets.pyx | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 85dd25438ab..d3d1093cbfa 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -10,6 +10,9 @@ difference family as even for small parameters it already takes time to run. Instead, its output has been stored into a database :mod:`sage.combinat.designs.database`. If the backtracker is improved, then one might want to update this database with more values. + +Classes and methods +------------------- """ include "sage/ext/stdsage.pxi" @@ -20,7 +23,7 @@ from libc.limits cimport UINT_MAX from libc.string cimport memset from libc.stdlib cimport qsort -from sage.ext.memory cimport check_malloc +from sage.ext.memory cimport check_malloc, check_calloc from sage.libs.gmp.types cimport mpz_t from sage.rings.integer cimport Integer,smallInteger @@ -29,12 +32,13 @@ cdef class EvenlyDistributedSetsBacktracker: r""" Set of evenly distributed subsets in finite fields. - Let `K` be a finite field of cardinality `q` and `k` an integer so that - `k(k-1)` divides `q-1`. Let `H = K^*` be the multiplicative group of - invertible elements in `K`. A `k`-*evenly distributed set* in `K` is a set - `B = \{b_1, b_2, \ldots, b_k\}` of `k` elements of `K` so that the `k(k-1)` - differences `\Delta B = \{b_i - b_j; i \not= j\}` fill each coset modulo - `H^{2(q-1)/(k(k-1))}` exactly twice. + **Definition:** Let `K` be a finite field of cardinality `q` and `k` an + integer so that `k(k-1)` divides `q-1`. Let `H = K^*` be the + multiplicative group of invertible elements in `K`. A `k`-*evenly + distributed set* in `K` is a set `B = \{b_1, b_2, \ldots, b_k\}` of `k` + elements of `K` so that the `k(k-1)` differences `\Delta B = \{b_i - + b_j; i \not= j\}` fill each coset modulo `H^{2(q-1)/(k(k-1))}` exactly + twice. Evenly distributed sets were introduced by Wilson [Wi72]_. He proved that for any `k`, and for any prime power `q` large enough such that `k(k-1)` @@ -43,9 +47,9 @@ cdef class EvenlyDistributedSetsBacktracker: not provide a simple method to generate them. From a `k`-evenly distributed set, it is straightforward to build a - `(q,k,1)`-difference family. Another approach to generate difference family, - somehow dual to this one, is via radical difference family (see in - particular + `(q,k,1)`-difference family (see :meth:`to_difference_family`). Another + approach to generate a difference family, somehow dual to this one, is via + radical difference family (see in particular :func:`~sage.combinat.designs.difference_family.radical_difference_family` from the module :mod:`~sage.combinat.designs.difference_family`). @@ -63,13 +67,12 @@ cdef class EvenlyDistributedSetsBacktracker: intermediate steps of the iterator. This is mainly intended for debugging purpose. Setting it to ``True`` will considerably slow the iteration. - EXAMPLES:: - - sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker + EXAMPLES: The main part of the code is contained in the iterator. To get one evenly distributed set just do:: + sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker sage: E = EvenlyDistributedSetsBacktracker(Zmod(151),6) sage: B = E.an_element() sage: B @@ -145,10 +148,10 @@ cdef class EvenlyDistributedSetsBacktracker: sage: EvenlyDistributedSetsBacktracker(Zmod(71),7) Traceback (most recent call last): ... - ValueError: k(k-1)=42 does not divide q-1=71 + ValueError: k(k-1)=42 does not divide q-1=70 """ - self.check = 1 if check else 0 - self.up_to_isom = 1 if up_to_isomorphism else 0 + self.check = bool(check) + self.up_to_isom = bool(up_to_isomorphism) self.count = 0 cdef unsigned int i,j,ell @@ -158,7 +161,7 @@ cdef class EvenlyDistributedSetsBacktracker: cdef unsigned int q = K.cardinality() cdef unsigned int e = k*(k-1)/2 if (q-1) % (2*e) != 0: - raise ValueError("k(k-1)={} does not divide q-1={}".format(k*(k-1),q)) + raise ValueError("k(k-1)={} does not divide q-1={}".format(k*(k-1),q-1)) cdef unsigned int m = (q-1)/e self.q = q @@ -166,18 +169,19 @@ cdef class EvenlyDistributedSetsBacktracker: self.k = k self.K = K - self.diff = check_malloc(q*sizeof(unsigned int *)) - self.diff[0] = check_malloc(q*q*sizeof(unsigned int)) + self.diff = check_calloc(q, sizeof(unsigned int *)) + self.diff[0] = check_malloc(q*q*sizeof(unsigned int)) for i in range(1,self.q): self.diff[i] = self.diff[i-1] + q - self.ratio = check_malloc(q*sizeof(unsigned int *)) - self.ratio[0] = check_malloc(q*q*sizeof(unsigned int)) + + self.ratio = check_calloc(q, sizeof(unsigned int *)) + self.ratio[0] = check_malloc(q*q*sizeof(unsigned int)) for i in range(1,self.q): self.ratio[i] = self.ratio[i-1] + q - self.B = check_malloc(k*sizeof(unsigned int)) + self.B = check_malloc(k*sizeof(unsigned int)) self.cosets = check_malloc(e*sizeof(unsigned int)) - self.t = check_malloc(e*sizeof(unsigned int)) + self.t = check_malloc(e*sizeof(unsigned int)) x = K.multiplicative_generator() list_K = [] @@ -202,8 +206,12 @@ cdef class EvenlyDistributedSetsBacktracker: r""" Given an evenly distributed set ``B`` convert it to a difference family. - This is useful if you want to obtain the difference family from the - output of the iterator. + As for any `x\in K^*=H` we have `|\Delta B \cap x + H^{2(q-1)/(k(k-1))}|=2` (see :class:`EvenlyDistributedSetsBacktracker`), + the difference family is produced as `\{xB:x\in H^{2(q-1)/(k(k-1))}\}` + + This method is useful if you want to obtain the difference family from + the output of the iterator. EXAMPLES:: @@ -225,7 +233,8 @@ cdef class EvenlyDistributedSetsBacktracker: r""" Return an evenly distributed set. - If there is no such subset raise an ``EmptySetError``. + If there is no such subset raise an + :class:`~sage.categories.sets_cat.EmptySetError`. EXAMPLES:: @@ -297,7 +306,11 @@ cdef class EvenlyDistributedSetsBacktracker: def _B_automorphisms(self): r""" - Check whether B is minimal among its relabelization. + Check whether `self.B` is minimal among its relabelization. + + If `B=\{x_1,...,x_k\}` and contains 0 and 1, then for any two distinct + `i,j` we define `f_{ij} : x \mapsto (x-x_j)/(x_i-x_j)` which maps `B` on + a set of size `k` containing 0 and 1. This is an internal function and should only be call by the backtracker implemented in the method `__iter__`. @@ -392,7 +405,7 @@ cdef class EvenlyDistributedSetsBacktracker: B[1] = 0 # the element 1 in K memset(self.cosets, 0, e * sizeof(unsigned int)) - memset(self.t, 0, e * sizeof(unsigned int)) + memset(self.t, 0, e * sizeof(unsigned int)) self.cosets[0] = 1 # the coset of 1 From 19c4fd2fb9737cc459c9e4747d09f87e6ad3ab94 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 19 Apr 2015 22:57:37 +0200 Subject: [PATCH 391/665] Trac 17662: remove the False from the database --- src/sage/combinat/designs/database.py | 14 -------------- src/sage/combinat/designs/difference_family.py | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 4f06bc87eae..768c3f8877a 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -4268,7 +4268,6 @@ def RBIBD_120_8_1(): 5: { 41: (None, [0, 1, 13, 38, 31]), 61: (None, [0, 1, 26, 11, 7]), - 81: False, 101: (None, [0, 1, 12, 43, 81]), 121: (a**2 + 7*a + 2, [0, 1, a, 9*a + 5, 3*a + 1]), 181: (None, [0, 1, 21, 47, 123]), @@ -4311,8 +4310,6 @@ def RBIBD_120_8_1(): 6: { 31: (None, [0, 1, 3, 12, 18, 8]), - 61: False, - 121: False, 151: (None, [0, 1, 69, 36, 57, 89]), 181: (None, [0, 1, 14, 4, 59, 139]), 211: (None, [0, 1, 24, 141, 128, 202]), @@ -4352,10 +4349,7 @@ def RBIBD_120_8_1(): }, 7: { - 43: False, - 127: False, 169: (a**2 + 12*a + 2, [0, 1, a, 5*a + 3, 11*a + 10, 11*a + 6, 5*a + 6]), - 211: False, 337: (None, [0, 1, 10, 28, 80, 224, 129]), 379: (None, [0, 1, 9, 175, 287, 14, 271]), 421: (None, [0, 1, 26, 4, 191, 250, 298]), @@ -4381,10 +4375,6 @@ def RBIBD_120_8_1(): }, 8: { - 113: False, - 169: False, - 281: False, - 337: False, 449: (None, [0, 1, 3, 332, 8, 104, 381, 61]), 617: (None, [0, 1, 3, 610, 397, 318, 465, 84]), 673: (None, [0, 1, 20, 355, 92, 491, 315, 478]), @@ -4404,10 +4394,7 @@ def RBIBD_120_8_1(): 9: { 73: (None, [0, 1, 5, 21, 59, 18, 12, 51, 49]), - 289: False, - 361: False, 433: (None, [0, 1, 5, 145, 347, 248, 57, 267, 110]), - 577: False, 937: (None, [0, 1, 5, 265, 828, 773, 328, 587, 866]), 1009: (None, [0, 1, 11, 251, 944, 497, 700, 99, 545]), 1153: (None, [0, 1, 5, 522, 1116, 495, 215, 859, 167]), @@ -4420,7 +4407,6 @@ def RBIBD_120_8_1(): }, 10:{ - 991: False, 1171: (None, [0, 1, 817, 856, 143, 881, 833, 82, 870, 564]), 1531: (None, [0, 1, 61, 1109, 417, 590, 1273, 11, 1445, 326]), 1621: (None, [0, 1, 52, 111, 779, 365, 1225, 378, 535, 1012]), diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 76d6ac7514d..7ec78309544 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -1230,7 +1230,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return G,df - elif l == 1 and k in EDS and v in EDS[k] and EDS[k][v] is not False: + elif l == 1 and k in EDS and v in EDS[k]: if existence: return True elif explain_construction: From 5e4ad59ff71c603797f7fd58d36a714a66ee6cff Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 20 Apr 2015 09:43:57 -0400 Subject: [PATCH 392/665] changed theta_qt with 1/q and 1/t to omega_qt plus adjustments to doc strings --- src/sage/combinat/sf/macdonald.py | 30 ++++++++++++++++-------------- src/sage/combinat/sf/sfa.py | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 369293a0eed..3bcb16f1ca7 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -483,7 +483,7 @@ def Ht(self): sage: Ht = Sym.macdonald().Ht() sage: s = Sym.schur() sage: Ht(s([2,1])) - ((-q)/(-q*t^2+t^3+q^2-q*t))*McdHt[1, 1, 1] + ((q^2+q*t+t^2)/(-q^2*t^2+q^3+t^3-q*t))*McdHt[2, 1] + ((-t)/(q^3-q^2*t-q*t+t^2))*McdHt[3] + ((-q)/(-q*t^2+t^3+q^2-q*t))*McdHt[1, 1, 1] + ((q^2+q*t+t^2)/(-q^2*t^2+q^3+t^3-q*t))*McdHt[2, 1] + (t/(-q^3+q^2*t+q*t-t^2))*McdHt[3] sage: Ht(s([2])) ((-q)/(-q+t))*McdHt[1, 1] + (t/(-q+t))*McdHt[2] """ @@ -907,7 +907,7 @@ def _multiply(self, left, right): sage: Q._multiply(Q[1],Q[2]) McdQ[2, 1] + ((q^2*t-q^2+q*t-q+t-1)/(q^2*t-1))*McdQ[3] sage: Ht._multiply(Ht[1],Ht[2]) - ((-q^2+1)/(-q^2+t))*McdHt[2, 1] + ((t-1)/(-q^2+t))*McdHt[3] + ((-q^2+1)/(-q^2+t))*McdHt[2, 1] + ((-t+1)/(q^2-t))*McdHt[3] """ return self( self._s(left)*self._s(right) ) @@ -1241,11 +1241,12 @@ def _self_to_m(self, x): sage: m(H[2,1]) ((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3] """ + (q,t)=QQqt.gens() return self._m._from_dict({ part2: - self._base(sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, mu)).subs(q=self.q,t=1/self.t) - * self.t**mu.weighted_size() - for mu in x.homogeneous_component(d).support())) - for d in range(x.degree()+1) for part2 in Partitions(d) }) + self._base(sum(x.coefficient(mu)* (QQqt(self._Lmunu(part2, mu)).subs(t=1/t)* + t**mu.weighted_size()).subs(q=self.q,t=self.t) + for mu in x.homogeneous_component(d).support())) + for d in range(x.degree()+1) for part2 in Partitions(d) }) def _m_to_self( self, f ): r""" @@ -1288,16 +1289,17 @@ def _m_to_self( self, f ): McdH[2, 1] """ if self.t == 1: - subsval = 1 / self.q + g = f.omega_qt(q=self.q, t=0) fl = lambda x: x.conjugate() + mu_to_H = lambda mu: self._self_to_m(self(mu.conjugate())).omega_qt(q=self.q, t=0) else: - subsval = self.t + g = f.theta_qt(q=self.t, t=0) fl = lambda x: x - g = f.theta_qt(q=subsval, t=0) + mu_to_H = lambda mu: self._self_to_m(self(mu)).theta_qt(q=self.t, t=0) out = {} while not g.is_zero(): sprt = g.support() - Hmu = self._self_to_m( self(fl(sprt[-1])) ).theta_qt(q=subsval, t=0) + Hmu = mu_to_H(sprt[-1]) out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1]) / Hmu.coefficient(sprt[-1])) g -= out[fl(sprt[-1])] * Hmu return self._from_dict(out) @@ -1469,16 +1471,16 @@ def _m_to_self( self, f ): """ if self.t == 1: - subsval = ~self.q + subsval = self.q fl = lambda x: x.conjugate() else: - subsval = ~self.t + subsval = self.t fl = lambda x: x - g = f.theta_qt(q=subsval, t=0) + g = f.omega_qt(q=subsval, t=0) out = {} while not g.is_zero(): sprt = g.support() - Htmu = self._self_to_m(self(fl(sprt[-1]))).theta_qt(q=subsval, t=0) + Htmu = self._self_to_m(self(fl(sprt[-1]))).omega_qt(q=subsval, t=0) out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1]) / Htmu.coefficient(sprt[-1])) g -= out[fl(sprt[-1])] * Htmu return self._from_dict(out) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 5a2c8dd2342..648200756ff 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -4063,7 +4063,7 @@ def nabla(self, q=None, t=None, power=1): sage: s(1).nabla() s[] sage: s([2,1]).nabla(power=-1) - ((-q-t)/(q^2*t^2))*s[2, 1] + ((-q^2-q*t-t^2)/(q^3*t^3))*s[3] + ((-q-t)/(q^2*t^2))*s[2, 1] + ((q^2+q*t+t^2)/(-q^3*t^3))*s[3] sage: (s([2])+s([3])).nabla() (-q*t)*s[1, 1] + (q^3*t^2+q^2*t^3)*s[1, 1, 1] + q^2*t^2*s[2, 1] """ From 230fd550f880c78287838c3574b1ca718b85c40e Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Mon, 20 Apr 2015 16:01:21 +0200 Subject: [PATCH 393/665] 16659: some doc improvement --- .../finite_dimensional_algebras_with_basis.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6d2f847ae71..474d3af3de0 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -429,6 +429,11 @@ def central_orthogonal_idempotents(self): - ``self`` -- a finite dimensional algebra + OUTPUT: + + - a list of a complete set of orthogonal idempotents of the + algebra. + ALGORITHM: Let '\overline{e}' be a central orthogonal idempotent of the @@ -459,11 +464,13 @@ def central_orthogonal_idempotents(self): 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] - sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) + sage: all(e*e == e for e in orth) + True + sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) True - We construct the minimum orthogonal idempotents of the `0`-Hecke - monoid algebra:: + We construct the orthogonal idempotents of the `0`-Hecke monoid + algebra:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: W = WeylGroup(['A', 3]); W.rename("W") @@ -473,9 +480,10 @@ def central_orthogonal_idempotents(self): A submonoid of (Maps from W to itself) with 3 generators sage: A = M.algebra(QQ) sage: orth = A.central_orthogonal_idempotents() - sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) + sage: all(e*e == e for e in orth) + True + sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) True - REFERENCES: @@ -500,9 +508,10 @@ def lift(idemp, one): orths = [lift(x.lift(), one) for x in Aquo.central_orthogonal_idempotents()] # Construction of the orthogonal idempotents idems = [] + f = 0 for g in orths: - f = sum(idems) # 0 if idems is empty idems.append(lift((one - f) * g * (one - f), one)) + f = f + idems[-1] return idems @cached_method From dee7f741ef3c4d01cbbc12983aefb0a431409be6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 20 Apr 2015 11:21:55 +0200 Subject: [PATCH 394/665] Trac 17662: better cuts --- .../designs/evenly_distributed_sets.pyx | 72 +++++++++++-------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index d3d1093cbfa..dcefd2147e2 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -21,10 +21,8 @@ cimport cython from libc.limits cimport UINT_MAX from libc.string cimport memset -from libc.stdlib cimport qsort from sage.ext.memory cimport check_malloc, check_calloc -from sage.libs.gmp.types cimport mpz_t from sage.rings.integer cimport Integer,smallInteger @@ -96,7 +94,6 @@ cdef class EvenlyDistributedSetsBacktracker: [0, 1, 9, 3] [0, 1, 8, 10] - sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=True) sage: for B in E: print B [0, 1, 11, 5] @@ -117,6 +114,8 @@ cdef class EvenlyDistributedSetsBacktracker: cdef unsigned int e # k(k-1)/2 cdef unsigned int ** diff # qxq array: diff[x][y] = x - y cdef unsigned int ** ratio # qxq array: ratio[x][y] = x / y + cdef unsigned int * min_orb # q array : min_orb[x] = min {x, 1-x, 1/x, + # 1/(1-x), (x-1)/x, x/(x-1)} # DYNAMIC DATA cdef unsigned int * B # current stack of elements of {0,...,q-1} @@ -130,6 +129,7 @@ cdef class EvenlyDistributedSetsBacktracker: if self.ratio != NULL: sage_free(self.ratio[0]) sage_free(self.ratio) + sage_free(self.min_orb) sage_free(self.B) sage_free(self.cosets) sage_free(self.t) @@ -179,9 +179,10 @@ cdef class EvenlyDistributedSetsBacktracker: for i in range(1,self.q): self.ratio[i] = self.ratio[i-1] + q - self.B = check_malloc(k*sizeof(unsigned int)) - self.cosets = check_malloc(e*sizeof(unsigned int)) - self.t = check_malloc(e*sizeof(unsigned int)) + self.B = check_malloc(k*sizeof(unsigned int)) + self.min_orb = check_malloc(q*sizeof(unsigned int)) + self.cosets = check_malloc(e*sizeof(unsigned int)) + self.t = check_malloc(e*sizeof(unsigned int)) x = K.multiplicative_generator() list_K = [] @@ -190,11 +191,18 @@ cdef class EvenlyDistributedSetsBacktracker: list_K.append(K.zero()) self.list_K = list_K K_to_int = self.K_to_int = {y:i for i,y in enumerate(list_K)} - assert self.K_to_int[K.zero()] == q-1 - assert self.K_to_int[K.one()] == 0 + + zero = K.zero() + one = K.one() + assert self.K_to_int[zero] == q-1 + assert self.K_to_int[one] == 0 assert set(K) == set(list_K) + self.min_orb[0] = self.min_orb[q-1] = UINT_MAX for i,x in enumerate(self.list_K): + if x != zero and x != one: + self.min_orb[i] = min(K_to_int[z] for z in \ + [x, one/x, one-x, one/(one-x), (x-one)/x, x/(x-one)]) for j,y in enumerate(self.list_K): self.diff[i][j] = K_to_int[x-y] if y: @@ -458,32 +466,35 @@ cdef class EvenlyDistributedSetsBacktracker: Add the element ``x`` to ``B`` in position kk if the resulting set is still evenly distributed. """ - cdef unsigned int i,j - cdef unsigned int tmp + cdef unsigned int i, j, x_m_i, x_m_j cdef unsigned int m = (self.q-1)/self.e - # we check that we do not get a smaller evenly distributed set by a - # relabeling of the form - # 1. z -> (z - x) / (B[i] - x) that maps x -> 0 and B[i] -> 1 - # 2. z -> (z - B[i]) / (x - B[i]) that maps B[i] -> 0 and x -> 1 - if kk > 2: - for i in range(kk): - # isom of form 1 - tmp = self.diff[self.B[i]][x] - for j in range(kk): - if j == i: - continue - if self.ratio[tmp][self.diff[self.B[j]][x]] < self.B[2]: - return 0 - - # isom of form 2 - tmp = self.diff[x][self.B[i]] - for j in range(kk): - if j == i: - continue - if self.ratio[self.diff[self.B[j]][self.B[i]]][tmp] < self.B[2]: + # We first check that applying some automorphisms we will not get an + # element smaller than B[2]. We should test all linear functions that + # send a subset of the form {x, B[i], B[j]} to {0, 1, z}. + # Given one such function, the values of the other are 1/z, 1-z, + # 1/(1-z), (z-1)/z and z/(z-1). The attribute 'min_orbit[z]' is + # exactly the minimum among these values. + # So it is enough to test one of these functions. We choose + # t -> (x - t)/ (x - B[j]) + # (that maps x to 0 and B[i] to 1). Its value at B[i] is just + # z = (x - B[i]) / (x - B[j]). + # + # In the special case when kk=2, or equivalently when we are testing if x + # fits as a new B[2], then we just check that x is the minimum among + # {x, 1/x, 1-x, 1/(1-x), (x-1)/x and x/(x-1)}. + if kk == 2: + if self.min_orb[x] < x: + return 0 + else: + for i in range(1,kk): + x_m_i = self.diff[x][self.B[i]] + for j in range(i): + x_m_j = self.diff[x][self.B[j]] + if self.min_orb[self.ratio[x_m_i][x_m_j]] < self.B[2]: return 0 + # Next we compute the cosets hit by the differences for j in range(kk): i = self.diff[x][self.B[j]] / m if self.cosets[i] or self.t[i]: @@ -491,6 +502,7 @@ cdef class EvenlyDistributedSetsBacktracker: return 0 self.t[i] = 1 + # If everything went smoothly, we add x to B self.B[kk] = x for i in range(self.e): if self.t[i]: From e25a95ecf922156826c5fee75dc73ae62deb279f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 15:10:03 +0200 Subject: [PATCH 395/665] trac #18260: Small fix for directed graphs --- src/sage/graphs/centrality.pyx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index c49b426969b..2a5e3c7780e 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -42,7 +42,7 @@ def centrality_betweenness(G, exact=False, normalize=True): INPUT: - - ``G`` -- a graph + - ``G`` -- a (di)graph - ``exact`` (boolean, default: ``False``) -- whether to compute over rationals or on ``double`` C variables. @@ -60,7 +60,7 @@ def centrality_betweenness(G, exact=False, normalize=True): For every vertex `s`, we compute the value of `c_s(v)` for all `v`, using the following remark (see [Brandes01]_): - Let `v_1,...,v_k` be the neighbors of `v` such that + Let `v_1,...,v_k` be the out-neighbors of `v` such that `dist(s,v_i)=dist(s,v)+1`. Then .. MATH:: @@ -77,7 +77,7 @@ def centrality_betweenness(G, exact=False, normalize=True): sage: from sage.graphs.centrality import centrality_betweenness sage: centrality_betweenness(digraphs.Circuit(6)) # abs tol 1e-10 - {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0} + {0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5, 4: 0.5, 5: 0.5} sage: centrality_betweenness(graphs.CycleGraph(6)) # abs tol 1e-10 {0: 0.2, 1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2} @@ -147,7 +147,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): # A second copy, to remember the edges used during the BFS (see doc) cdef short_digraph bfs_dag - init_short_digraph(bfs_dag, G, edge_labelled = False) + init_reverse(bfs_dag, g) cdef int n = g.n @@ -304,12 +304,15 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): mpq_clear(n_paths_from_source[i]) mpq_clear(mpq_tmp) - if normalize: - betweenness_list = [x/((n-1)*(n-2)) for x in betweenness_list] - else: + if not G.is_directed(): betweenness_list = [x/2 for x in betweenness_list] - if G.is_directed(): - betweenness_list = [2*x for x in betweenness_list] + + if normalize: + if G.is_directed(): + betweenness_list = [ x/((n-1)*(n-2)) for x in betweenness_list] + else: + betweenness_list = [2*x/((n-1)*(n-2)) for x in betweenness_list] + free_short_digraph(g) free_short_digraph(bfs_dag) bitset_free(seen) From b83d82833e0b6fcce0700f24c6c029958c761311 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 15:30:16 +0200 Subject: [PATCH 396/665] trac #18260: Move centrality functions from graph.py to generic_graph.py --- src/sage/graphs/generic_graph.py | 96 ++++++++++++++++++++++++++++++++ src/sage/graphs/graph.py | 95 +------------------------------ 2 files changed, 97 insertions(+), 94 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index f06fd429f7d..2d256f3a234 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12738,6 +12738,102 @@ def periphery(self): return [] return [v for v in e if e[v]==r] + + ### Centrality + + def centrality_betweenness(self, k=None, normalized=True, weight=None, + endpoints=False, seed=None, exact=False, + algorithm=None): + r""" + Returns the betweenness centrality (fraction of number of + shortest paths that go through each vertex) as a dictionary + keyed by vertices. The betweenness is normalized by default to + be in range (0,1). + + Measures of the centrality of a vertex within a graph determine + the relative importance of that vertex to its graph. Vertices + that occur on more shortest paths between other vertices have + higher betweenness than vertices that occur on less. + + INPUT: + + - ``normalized`` - boolean (default True) - if set to False, + result is not normalized. + + - ``k`` - integer or None (default None) - if set to an integer, use + ``k`` node samples to estimate betweenness. Higher values give better + approximations. Not available when ``algorithm="Sage"``. + + - ``weight`` - None or string. If set to a string, use that attribute of + the nodes as weight. ``weight = True`` is equivalent to ``weight = + "weight"``. Not available when ``algorithm="Sage"``. + + - ``endpoints`` - Boolean. If set to True it includes the endpoints in + the shortest paths count. Not available when ``algorithm="Sage"``. + + - ``exact`` (boolean, default: ``False``) -- whether to compute over + rationals or on ``double`` C variables. Not available when + ``algorithm="NetworkX"``. + + - ``algorithm`` (default: ``None``) -- can be either ``"Sage"`` (see + :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In the + latter case, Sage's algorithm will be used whenever possible. + + REFERENCE: + + .. [Brandes2003] Ulrik Brandes. (2003). Faster Evaluation of + Shortest-Path Based Centrality Indices. [Online] Available: + http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.1504 + + EXAMPLES:: + + sage: g = graphs.ChvatalGraph() + sage: g.centrality_betweenness() # abs tol 1e-10 + {0: 0.06969696969696969, 1: 0.06969696969696969, + 2: 0.0606060606060606, 3: 0.0606060606060606, + 4: 0.06969696969696969, 5: 0.06969696969696969, + 6: 0.0606060606060606, 7: 0.0606060606060606, + 8: 0.0606060606060606, 9: 0.0606060606060606, + 10: 0.0606060606060606, 11: 0.0606060606060606} + sage: g.centrality_betweenness(normalized=False) # abs tol 1e-10 + {0: 3.833333333333333, 1: 3.833333333333333, 2: 3.333333333333333, + 3: 3.333333333333333, 4: 3.833333333333333, 5: 3.833333333333333, + 6: 3.333333333333333, 7: 3.333333333333333, 8: 3.333333333333333, + 9: 3.333333333333333, 10: 3.333333333333333, + 11: 3.333333333333333} + sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) + sage: D.show(figsize=[2,2]) + sage: D = D.to_undirected() + sage: D.show(figsize=[2,2]) + sage: D.centrality_betweenness() # abs tol abs 1e-10 + {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0} + """ + if algorithm == "NetworkX" and exact: + raise ValueError("'exact' is not available with the NetworkX implementation") + if (algorithm is None and + seed is None and + weight is None and + endpoints is False and + k is None): + algorithm = "Sage" + elif algorithm is None: + algorithm = "NetworkX" + + if algorithm == "Sage": + from centrality import centrality_betweenness + return centrality_betweenness(self, normalize = normalized,exact=exact) + elif algorithm == "NetworkX": + import networkx + return networkx.betweenness_centrality(self.networkx_graph(copy=False), + k=k, + normalized=normalized, + weight=weight, + endpoints=endpoints, + seed=seed) + else: + raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") + + ### Paths def interior_paths(self, start, end): diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 2b92d65ed91..362fb8d40af 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4604,100 +4604,7 @@ def convexity_properties(self): from sage.graphs.convexity_properties import ConvexityProperties return ConvexityProperties(self) - ### Centrality - - def centrality_betweenness(self, k=None, normalized=True, weight=None, - endpoints=False, seed=None, exact=False, - algorithm=None): - r""" - Returns the betweenness centrality (fraction of number of - shortest paths that go through each vertex) as a dictionary - keyed by vertices. The betweenness is normalized by default to - be in range (0,1). - - Measures of the centrality of a vertex within a graph determine - the relative importance of that vertex to its graph. Vertices - that occur on more shortest paths between other vertices have - higher betweenness than vertices that occur on less. - - INPUT: - - - ``normalized`` - boolean (default True) - if set to False, - result is not normalized. - - - ``k`` - integer or None (default None) - if set to an integer, use - ``k`` node samples to estimate betweenness. Higher values give better - approximations. Not available when ``algorithm="Sage"``. - - - ``weight`` - None or string. If set to a string, use that attribute of - the nodes as weight. ``weight = True`` is equivalent to ``weight = - "weight"``. Not available when ``algorithm="Sage"``. - - - ``endpoints`` - Boolean. If set to True it includes the endpoints in - the shortest paths count. Not available when ``algorithm="Sage"``. - - - ``exact`` (boolean, default: ``False``) -- whether to compute over - rationals or on ``double`` C variables. Not available when - ``algorithm="NetworkX"``. - - - ``algorithm`` (default: ``None``) -- can be either ``"Sage"`` (see - :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In the - latter case, Sage's algorithm will be used whenever possible. - - REFERENCE: - - .. [Brandes2003] Ulrik Brandes. (2003). Faster Evaluation of - Shortest-Path Based Centrality Indices. [Online] Available: - http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.1504 - - EXAMPLES:: - - sage: g = graphs.ChvatalGraph() - sage: g.centrality_betweenness() # abs tol 1e-10 - {0: 0.06969696969696969, 1: 0.06969696969696969, - 2: 0.0606060606060606, 3: 0.0606060606060606, - 4: 0.06969696969696969, 5: 0.06969696969696969, - 6: 0.0606060606060606, 7: 0.0606060606060606, - 8: 0.0606060606060606, 9: 0.0606060606060606, - 10: 0.0606060606060606, 11: 0.0606060606060606} - sage: g.centrality_betweenness(normalized=False) # abs tol 1e-10 - {0: 3.833333333333333, 1: 3.833333333333333, 2: 3.333333333333333, - 3: 3.333333333333333, 4: 3.833333333333333, 5: 3.833333333333333, - 6: 3.333333333333333, 7: 3.333333333333333, 8: 3.333333333333333, - 9: 3.333333333333333, 10: 3.333333333333333, - 11: 3.333333333333333} - sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: D.show(figsize=[2,2]) - sage: D = D.to_undirected() - sage: D.show(figsize=[2,2]) - sage: D.centrality_betweenness() # abs tol abs 1e-10 - {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0} - """ - if algorithm == "NetworkX" and exact: - raise ValueError("'exact' is not available with the NetworkX implementation") - if (algorithm is None and - seed is None and - weight is None and - endpoints is False and - k is None): - algorithm = "Sage" - elif algorithm is None: - algorithm = "NetworkX" - - if algorithm == "Sage": - from centrality import centrality_betweenness - return centrality_betweenness(self, normalize = normalized,exact=exact) - elif algorithm == "NetworkX": - import networkx - return networkx.betweenness_centrality(self.networkx_graph(copy=False), - k=k, - normalized=normalized, - weight=weight, - endpoints=endpoints, - seed=seed) - else: - raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") - + # Centrality def centrality_degree(self, v=None): r""" Returns the degree centrality (fraction of vertices connected to) From e55042e6eae922a7ea483fc1a62ef1694071b38d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 16:25:37 +0200 Subject: [PATCH 397/665] trac #18260: A new doctest --- src/sage/graphs/generic_graph.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 2d256f3a234..997c95d9ef0 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12738,7 +12738,6 @@ def periphery(self): return [] return [v for v in e if e[v]==r] - ### Centrality def centrality_betweenness(self, k=None, normalized=True, weight=None, @@ -12807,6 +12806,18 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, sage: D.show(figsize=[2,2]) sage: D.centrality_betweenness() # abs tol abs 1e-10 {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0} + + TESTS:: + + sage: tests = ([graphs.RandomGNP(30,.1) for i in range(10)]+ + ....: [digraphs.RandomDirectedGNP(30,.1) for i in range(10)]) + sage: for g in tests: + ....: r1 = g.centrality_betweenness(algorithm="Sage",exact=0) + ....: r2 = g.centrality_betweenness(algorithm="Sage",exact=1) + ....: r3 = g.centrality_betweenness(algorithm="NetworkX") + ....: for x in g: + ....: if max([r1[x],r2[x],r3[x]])-min([r1[x],r2[x],r3[x]]) > 0.01: + ....: print "Error",x,[r1[x],r2[x],r3[x]] """ if algorithm == "NetworkX" and exact: raise ValueError("'exact' is not available with the NetworkX implementation") From 69354fcb35c701ea3aa4311381acc4f8319cf85a Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 20 Apr 2015 17:30:03 +0200 Subject: [PATCH 398/665] Set the default value of axes_labels_size to 1.6 --- src/sage/plot/graphics.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 085879c828d..16d9a4497e4 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -150,7 +150,7 @@ def __init__(self): self._bbox_extra_artists = [] self._extra_kwds = {} self._fontsize = 10 - self._axes_labels_size = 1.7 + self._axes_labels_size = 1.6 self._legend_colors = [] self._legend_opts = {} self._objects = [] @@ -474,7 +474,7 @@ def fontsize(self, s=None): Set the font size of axes labels and tick marks. Note that the relative size of the axes labels font w.r.t. the tick - marks font can be adjusted via :meth:`axes_labels_size`. + marks font can be adjusted via :meth:`axes_labels_size`. INPUT: @@ -521,7 +521,7 @@ def axes_labels_size(self, s=None): sage: p = plot(sin(x^2), (x, -3, 3), axes_labels=['$x$','$y$']) sage: p.axes_labels_size() # default value - 1.7 + 1.6 sage: p.axes_labels_size(2.5) sage: p.axes_labels_size() 2.5 @@ -536,7 +536,7 @@ def axes_labels_size(self, s=None): try: return self._axes_labels_size except AttributeError: - self._axes_labels_size = 1.7 + self._axes_labels_size = 1.6 return self._axes_labels_size self._axes_labels_size = float(s) @@ -898,7 +898,7 @@ def _rich_repr_(self, display_manager, **kwds): if output_container in display_manager.supported_output(): return display_manager.graphics_from_save( self.save, kwds, file_ext, output_container) - + def __str__(self): r""" Return string representation of this plot. @@ -1362,9 +1362,9 @@ def show(self, filename=None, linkmode=False, **kwds): strings; the first is used as the label for the horizontal axis, and the second for the vertical axis. - - ``axes_labels_size`` - (default: current setting -- 1.7) scale factor + - ``axes_labels_size`` - (default: current setting -- 1.6) scale factor relating the size of the axes labels with respect to the size of the - tick marks. + tick marks. - ``fontsize`` - (default: current setting -- 10) positive integer; used for axes labels; if you make this very large, @@ -1908,9 +1908,9 @@ def show(self, filename=None, linkmode=False, **kwds): specify ``ticks`` manually, this safety measure can be defeated:: sage: list_plot_loglog([(1,2),(2,3)], plotjoined=True, ticks=[[1],[1]]) - doctest:...: UserWarning: The x-axis contains fewer than 2 ticks; + doctest:...: UserWarning: The x-axis contains fewer than 2 ticks; the logarithmic scale of the plot may not be apparent to the reader. - doctest:...: UserWarning: The y-axis contains fewer than 2 ticks; + doctest:...: UserWarning: The y-axis contains fewer than 2 ticks; the logarithmic scale of the plot may not be apparent to the reader. Graphics object consisting of 1 graphics primitive @@ -2011,7 +2011,7 @@ def show(self, filename=None, linkmode=False, **kwds): else: html("" % filename) return - + from sage.repl.rich_output import get_display_manager dm = get_display_manager() dm.display_immediately(self, **kwds) @@ -2469,7 +2469,7 @@ def matplotlib(self, filename=None, sage: plot(x, typeset='garbage') doctest:...: RichReprWarning: Exception in _rich_repr_ while - displaying object: typeset must be set to one of 'default', + displaying object: typeset must be set to one of 'default', 'latex', or 'type1'; got 'garbage'. Graphics object consisting of 1 graphics primitive From d0032bb7aa341861c08b694d86f48a33c16acc4f Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 20 Apr 2015 16:27:51 +0200 Subject: [PATCH 399/665] Trac 17662: review commit - more documentation - remove a useless if --- src/sage/combinat/designs/bibd.py | 13 +++- .../combinat/designs/difference_family.py | 11 +++ .../designs/evenly_distributed_sets.pyx | 73 +++++++++++++++---- 3 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 6ddd574ab2f..2184da9a68b 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -151,7 +151,18 @@ def balanced_incomplete_block_design(v, k, existence=False, use_LJCR=False): sage: [v for v in xrange(150) if designs.balanced_incomplete_block_design(v,6,existence=True) is Unknown] [51, 61, 66, 76, 81, 96, 106, 111, 126, 136, 141] - But we know some inexistence results:: + Here are some constructions with `k \geq 7` and `v` a prime power:: + + sage: designs.balanced_incomplete_block_design(169,7) + (169,7,1)-Balanced Incomplete Block Design + sage: designs.balanced_incomplete_block_design(617,8) + (617,8,1)-Balanced Incomplete Block Design + sage: designs.balanced_incomplete_block_design(433,9) + (433,9,1)-Balanced Incomplete Block Design + sage: designs.balanced_incomplete_block_design(1171,10) + (1171,10,1)-Balanced Incomplete Block Design + + And we know some inexistence results:: sage: designs.balanced_incomplete_block_design(21,6,existence=True) False diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 7ec78309544..865e369ea84 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -25,6 +25,17 @@ REFERENCES: +.. [BJL99-1] T. Beth, D. Jungnickel, H. Lenz "Design theory Vol. I." + Second edition. Encyclopedia of Mathematics and its Applications, 69. Cambridge + University Press, (1999). + +.. [BLJ99-2] T. Beth, D. Jungnickel, H. Lenz "Design theory Vol. II." + Second edition. Encyclopedia of Mathematics and its Applications, 78. Cambridge + University Press, (1999). + +.. [Bo39] R. C. Bose, "On the construction of balanced incomplete block + designs", Ann. Eugenics, vol. 9, (1939), 353--399. + .. [Bu95] M. Buratti "On simple radical difference families", J. of Combinatorial Designs, vol. 3, no. 2 (1995) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index dcefd2147e2..2aef57e0fdb 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -35,14 +35,15 @@ cdef class EvenlyDistributedSetsBacktracker: multiplicative group of invertible elements in `K`. A `k`-*evenly distributed set* in `K` is a set `B = \{b_1, b_2, \ldots, b_k\}` of `k` elements of `K` so that the `k(k-1)` differences `\Delta B = \{b_i - - b_j; i \not= j\}` fill each coset modulo `H^{2(q-1)/(k(k-1))}` exactly + b_j; i \not= j\}` hit each coset modulo `H^{2(q-1)/(k(k-1))}` exactly twice. - Evenly distributed sets were introduced by Wilson [Wi72]_. He proved that - for any `k`, and for any prime power `q` large enough such that `k(k-1)` - divides `k` there exists a `k`-evenly distributed set in the field of - cardinality `q`. This existence result based on a counting argument does - not provide a simple method to generate them. + Evenly distributed sets were introduced by Wilson [Wi72]_ (see also + [BJL99-1]_, Chapter VII.6). He proved that for any `k`, and for any prime power + `q` large enough such that `k(k-1)` divides `k` there exists a `k`-evenly + distributed set in the field of cardinality `q`. This existence result based + on a counting argument (using Dirichlet theorem) does not provide a simple + method to generate them. From a `k`-evenly distributed set, it is straightforward to build a `(q,k,1)`-difference family (see :meth:`to_difference_family`). Another @@ -51,6 +52,13 @@ cdef class EvenlyDistributedSetsBacktracker: :func:`~sage.combinat.designs.difference_family.radical_difference_family` from the module :mod:`~sage.combinat.designs.difference_family`). + By default, this backtracker only considers evenly distributed sets up to + affine automorphisms, i.e. `B` is considered equivalent to `s B + t` for any + invertible element `s` and any element `t` in the field `K`. Note that the + set of differences is just multiplicatively translated by `s` as + `\Delta (s B + t) = s (\Delta B)`. This can be modified via the argument + ``up_to_isomorphisms`` (see the input section and the examples below). + INPUT: - ``K`` -- a finite field of cardinality `q` @@ -97,6 +105,40 @@ cdef class EvenlyDistributedSetsBacktracker: sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=True) sage: for B in E: print B [0, 1, 11, 5] + + Or only count them:: + + sage: for k in range(13, 200, 12): + ....: if is_prime_power(k): + ....: K = GF(k,'a') + ....: E1 = EvenlyDistributedSetsBacktracker(K, 4, False) + ....: E2 = EvenlyDistributedSetsBacktracker(K, 4, True) + ....: print "{:3} {:3} {:3}".format(k, E1.cardinality(), E2.cardinality()) + 13 4 1 + 25 40 4 + 37 12 1 + 49 24 2 + 61 12 1 + 73 12 1 + 97 24 2 + 109 60 5 + 121 168 14 + 157 24 2 + 169 60 5 + 181 84 7 + 193 168 14 + + Note that by definition, the number of evenly distributed sets up to + isomorphisms is at most `k(k-1)` times smaller than without isomorphisms. + But it might not be exactly `k(k-1)` as some of them might have symmetries:: + + sage: B = EvenlyDistributedSetsBacktracker(Zmod(13), 4).an_element() + sage: B + [0, 1, 11, 5] + sage: [9*x + 5 for x in B] + [5, 1, 0, 11] + sage: [3*x + 11 for x in B] + [11, 1, 5, 0] """ # PYTHON DATA cdef K # the underlying field @@ -198,7 +240,7 @@ cdef class EvenlyDistributedSetsBacktracker: assert self.K_to_int[one] == 0 assert set(K) == set(list_K) - self.min_orb[0] = self.min_orb[q-1] = UINT_MAX + self.min_orb[0] = self.min_orb[q-1] = 0 for i,x in enumerate(self.list_K): if x != zero and x != one: self.min_orb[i] = min(K_to_int[z] for z in \ @@ -316,9 +358,11 @@ cdef class EvenlyDistributedSetsBacktracker: r""" Check whether `self.B` is minimal among its relabelization. - If `B=\{x_1,...,x_k\}` and contains 0 and 1, then for any two distinct - `i,j` we define `f_{ij} : x \mapsto (x-x_j)/(x_i-x_j)` which maps `B` on - a set of size `k` containing 0 and 1. + If `B=\{b_1,...,b_k\}` is an evenly distributed set and contains `0` and + `1`, then for any two distinct `i,j` we define `f_{ij} : x \mapsto + (x-b_j)/(b_i-b_j)` which maps `B` on another evenly distributed set of + size `k` containing `0` and `1`. For each pair `i,j` we consider check + whether the set `f_{ij}(B)` is smaller than `B`. This is an internal function and should only be call by the backtracker implemented in the method `__iter__`. @@ -327,9 +371,9 @@ cdef class EvenlyDistributedSetsBacktracker: - ``False`` if ``self.B`` is not minimal - - ``True`` if ``self.B`` is minimal and ``self.up_to_isom = 1`` - - - the list of relabeled versions if ``self.B`` is minimal and ``self.up_to_isom = 0`` + - the list of evenly distributed sets isomorphs to ``self.B`` given as a + list of tuples if ``self.up_to_isom=0`` or list containing only + ``self.B`` as a tuple if ``self.up_to_isom=1``. TESTS:: @@ -377,8 +421,7 @@ cdef class EvenlyDistributedSetsBacktracker: if not self.up_to_isom: if not verify: BB.sort() - if BB > B: - relabs.add(tuple(BB)) + relabs.add(tuple(BB)) return sorted(relabs) From 7362f035239f8fdbc992888478a9f4b7d102193c Mon Sep 17 00:00:00 2001 From: Franco Saliola Date: Mon, 20 Apr 2015 16:14:41 +0000 Subject: [PATCH 400/665] 16659: some documentation and tests --- src/sage/categories/algebras.py | 6 +- .../categories/examples/finite_monoids.py | 1 - .../finite_dimensional_algebras_with_basis.py | 198 ++++++++++++------ 3 files changed, 134 insertions(+), 71 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 1702b4a3e31..32c7783e1df 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -245,7 +245,7 @@ def extra_super_categories(self): class Subobjects(SubobjectsCategory): - + class ElementMethods: def _mul_(self, right): @@ -256,8 +256,8 @@ def _mul_(self, right): - ``self``, ``right`` -- two elements - If B is a SubModuleWithBasis of A, then the multiplication law of B is - inherited from the multiplication of A. + If `B` is a `SubModuleWithBasis` of `A`, then the + multiplication law of `B` is inherited from `A`. EXAMPLES:: diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index 6e614d14840..6ae004d2f50 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -139,7 +139,6 @@ def an_element(self): """ return self(ZZ(42) % self.n) - class Element (ElementWrapper): wrapped_class = Integer diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 6d2f847ae71..6ff499393a1 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -47,7 +47,7 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: @cached_method - def radical_basis(self, cache_products=True): + def radical_basis(self): r""" Return a basis of the Jacobson radical of this algebra. @@ -68,11 +68,6 @@ def radical_basis(self, cache_products=True): of the seventeenth annual ACM symposium on Theory of computing. ACM, 1985. - INPUT: - - - ``cache_products`` -- a boolean (default: ``True``); if - ``True`` then all products computed in this method are cached. - OUTPUT: - a list of elements of ``self``. @@ -144,17 +139,13 @@ def radical_basis(self, cache_products=True): TESTS:: sage: A = KleinFourGroup().algebra(GF(2)) - sage: A.radical_basis(cache_products=True) - [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] - sage: A.radical_basis(cache_products=False) + sage: A.radical_basis() [B[()] + B[(1,2)(3,4)], B[(3,4)] + B[(1,2)(3,4)], B[(1,2)] + B[(1,2)(3,4)]] sage: A = KleinFourGroup().algebra(QQ, category=Monoids()) sage: A.radical_basis.__module__ 'sage.categories.finite_dimensional_algebras_with_basis' - sage: A.radical_basis(cache_products=True) - [] - sage: A.radical_basis(cache_products=False) + sage: A.radical_basis() [] """ F = self.base_ring() @@ -164,22 +155,27 @@ def radical_basis(self, cache_products=True): from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector - product_on_basis = self.product_on_basis - if cache_products is True: - product_on_basis = cached_function(product_on_basis) - if p == 0: - keys = list(self.basis().keys()) - cache = [{(i,j): c - for i in keys - for j,c in product_on_basis(y,i)} - for y in keys] - mat = [ [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) - for x in cache] - for y in cache] - + index_set = list(self.basis().keys()) + + cached_products = {} + for y in index_set: + for i in index_set: + cached_products[y, i] = self.product_on_basis(y, i) + + mat = [] + for y in index_set: + row = [] + for x in index_set: + row.append( F.sum(cached_products[x, j][i] * + cached_products[y, i][j] + for i in index_set + for j in index_set) ) + mat.append(row) mat = matrix(self.base_ring(), mat) + rad_basis = mat.kernel().basis() + else: # TODO: some finite field elements in Sage have both an # ``nth_root`` method and a ``pth_root`` method (such as ``GF(9,'a')``), @@ -395,30 +391,48 @@ def center(self): def principal_ideal(self, a, side='left'): r""" - Construct the ``side`` `A`-module generated by ``a``. + Construct the ``side`` module generated by ``a``. - EXAMPLE:: + EXAMPLES: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.principal_ideal(A.an_element()) - Free module generated by {0, 1, 2, 3} over Rational Field + In order to highlight the difference between left and right + principal ideals, our first example deals with a non commutative + algebra:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field + sage: x, y, a, b = A.basis() + + In this algebra, multiplication on the right by `x` + annihilates all basis elements but `x`:: + + sage: x*x, y*x, a*x, b*x + (x, 0, 0, 0) + + so the left ideal generated by `x` is one-dimensional:: + + sage: Ax = A.principal_ideal(x, side='left'); Ax + Free module generated by {0} over Rational Field + sage: [B.lift() for B in Ax.basis()] + [x] + + Multiplication on the left by `x` annihilates + only `x` and fixes the other basis elements:: + + sage: x*x, x*y, x*a, x*b + (x, 0, a, b) + so the right ideal generated by `x` is 3-dimensional:: + + sage: xA = A.principal_ideal(x, side='right'); xA + Free module generated by {0, 1, 2} over Rational Field + sage: [B.lift() for B in xA.basis()] + [x, a, b] """ - B = self.basis() - if side == 'left': - phi = self.module_morphism(on_basis=lambda i: a*B[i], - codomain=self, - triangular='lower') - elif side == 'right': - phi = self.module_morphism(on_basis=lambda i: B[i]*a, - codomain=self, - triangular='lower') - else: - raise Exception("Side must be ``left`` or ``right``") - ideal = phi.matrix().image() - #now let's make it a submodule of A - return self.submodule([self.from_vector(v) for v in ideal.basis()], - already_echelonized=True) + return self.submodule([(a * b if side=='right' else b * a) + for b in self.basis()]) def central_orthogonal_idempotents(self): r""" @@ -442,27 +456,30 @@ def central_orthogonal_idempotents(self): sage: import itertools sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: the path - algebra of the Kronecker quiver (containing the arrows a:x->y - and b:x->y) over Rational Field + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.central_orthogonal_idempotents() [y, x] + + :: + sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) sage: orth = A.central_orthogonal_idempotents(); orth - [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + - 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], - -B[0] + 1/2*B[4] + 1/2*B[8], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - - 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] - + 1/4*B[11]] - sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) - True - - We construct the minimum orthogonal idempotents of the `0`-Hecke + [-1/2*B[8] + 1/2*B[4], + 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], + 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], + -1/2*B[3] + 1/2*B[9], + B[0], + -B[0] + 1/2*B[4] + 1/2*B[8], + 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - 1/4*B[7], + -B[0] + 1/2*B[3] + 1/2*B[9], + B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] + + We construct the minimal orthogonal idempotents of the `0`-Hecke monoid algebra:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup @@ -473,9 +490,49 @@ def central_orthogonal_idempotents(self): A submonoid of (Maps from W to itself) with 3 generators sage: A = M.algebra(QQ) sage: orth = A.central_orthogonal_idempotents() - sage: all(e*f == f*e for e,f in itertools.product(orth, orth)) + sage: all(e * f == f * e for (e, f) in itertools.product(orth, orth)) + True + + TESTS: + + We test that the above idempotents are central orthogonal idempotents:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: E = A.central_orthogonal_idempotents() + sage: all(e.is_idempotent() for e in E) + True + sage: all(e * f == 0 for e in E for f in E if e != f) + True + sage: all(e * b == b * e for b in A.basis() for e in E) True + :: + + sage: Z12 = Monoids().Finite().example() + sage: A = Z12.algebra(QQ) + sage: E = A.central_orthogonal_idempotents() + sage: all(e.is_idempotent() for e in E) + True + sage: all(e * f == 0 for e in E for f in E if e != f) + True + sage: all(e * b == b * e for b in A.basis() for e in E) + True + + :: + + sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup + sage: W = WeylGroup(['A', 3]); W.rename("W") + sage: ambient_monoid = FiniteSetMaps(W, action="right") + sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) + sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()) + sage: A = M.algebra(QQ) + sage: E = A.central_orthogonal_idempotents() + sage: all(e.is_idempotent() for e in E) + True + sage: all(e * f == 0 for e in E for f in E if e != f) + True + sage: all(e * b == b * e for b in A.basis() for e in E) + True REFERENCES: @@ -593,12 +650,12 @@ def pierce_decomposition_component(self, ei, ej): INPUT: - ``self`` -- an algebra `A` - - `e_i` -- an orthogonal idempotent of ``self`` - - `e_j` -- an orthogonal idempotent of ``self`` + - `e_i` -- an idempotent of ``self`` + - `e_j` -- an idempotent of ``self`` OUTPUT: - - `e_i A e_j` as a subalgebra of ``self`` + - `e_i A e_j` as a subspace of ``self`` EXAMPLES:: @@ -626,14 +683,21 @@ def pierce_decomposition_component(self, ei, ej): def pierce_decomposition(self): r""" - Return the Pierce decomposition of ``self`` + Return the Pierce decomposition of ``self``. + + Let `A` be a finite dimensional algebra. + The Pierce decomposition of `A` is the + decomposition of `A` into the subspaces + + TODO: polish this OUTPUT: - - list of subalgebras `e_i A e_j` for `e_i, e_j` orthogonal - idempotents + The list of subspaces `e_i A e_j`, where `e_i` and `e_j` run + through a complete system of primitive orthogonal idempotents of + this algebra `A`. - EXAMPLES:: + EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: A.pierce_decomposition() From 731445932eb551241b7f4e0ad10a4d533850c1e7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 18:45:30 +0200 Subject: [PATCH 401/665] trac #18260: Broken link in the doc --- src/sage/graphs/generic_graph.py | 1 + src/sage/graphs/graph.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 997c95d9ef0..5166f2654c4 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -194,6 +194,7 @@ :widths: 30, 70 :delim: | + :meth:`~GenericGraph.centrality_betweenness` | Returns the betweenness centrality :meth:`~GenericGraph.distance` | Returns the (directed) distance from u to v in the (di)graph :meth:`~GenericGraph.distance_all_pairs` | Returns the distances between all pairs of vertices. :meth:`~GenericGraph.distances_distribution` | Returns the distances distribution of the (di)graph in a dictionary. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 362fb8d40af..881dbfbd1fd 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -31,7 +31,6 @@ :meth:`~Graph.centrality_closeness` | Returns the closeness centrality (1/average distance to all vertices) :meth:`~Graph.centrality_degree` | Returns the degree centrality - :meth:`~Graph.centrality_betweenness` | Returns the betweenness centrality **Graph properties:** From 4bc0de8139d72fb4a2c19cd3cb0d2f61e1b7bb60 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 19:31:57 +0200 Subject: [PATCH 402/665] trac #18260: Reviewer's comments --- src/sage/graphs/centrality.pyx | 3 ++- src/sage/graphs/generic_graph.py | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 2a5e3c7780e..0280ee658e5 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -110,7 +110,8 @@ def centrality_betweenness(G, exact=False, normalize=True): .. [Brandes01] Ulrik Brandes, A faster algorithm for betweenness centrality, - Journal of Mathematical Sociology 25.2 (2001): 163-177 + Journal of Mathematical Sociology 25.2 (2001): 163-177, + http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf """ if exact: return centrality_betweenness_C(G, 0,normalize=normalize) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 5166f2654c4..94d4bf2076a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12779,12 +12779,6 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In the latter case, Sage's algorithm will be used whenever possible. - REFERENCE: - - .. [Brandes2003] Ulrik Brandes. (2003). Faster Evaluation of - Shortest-Path Based Centrality Indices. [Online] Available: - http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.1504 - EXAMPLES:: sage: g = graphs.ChvatalGraph() From 487b3a29bc0b5eb4ec4b6b2ec0d5503dc77df461 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 20:46:46 +0200 Subject: [PATCH 403/665] trac #18262: regroup mallocs --- src/sage/graphs/centrality.pyx | 62 ++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 0280ee658e5..0bc9406b386 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -144,37 +144,42 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): # A copy of G, for faster neighbor enumeration cdef short_digraph g - init_short_digraph(g, G, edge_labelled = False) # A second copy, to remember the edges used during the BFS (see doc) cdef short_digraph bfs_dag - init_reverse(bfs_dag, g) - - cdef int n = g.n - # The vertices whose neighbors have been explored by the BFS - cdef bitset_t seen - bitset_init(seen,n) + cdef int n = G.order() - # The unexplored neighbors of vertices in 'seen' - cdef bitset_t next_layer - bitset_init(next_layer,n) + cdef bitset_t seen # Vertices whose neighbors have been explored + cdef bitset_t next_layer # Unexplored neighbors of vertices in 'seen' - cdef uint32_t * queue = sage_malloc(n*sizeof(uint32_t)) - cdef uint32_t * degrees = sage_malloc(n*sizeof(uint32_t)) + cdef uint32_t * queue # BFS queue + cdef uint32_t * degrees # degree[v] = nb of vertices which discovered v cdef numerical_type * n_paths_from_source cdef numerical_type * betweenness_source cdef numerical_type * betweenness cdef numerical_type mpq_tmp - n_paths_from_source = sage_malloc(n*sizeof(numerical_type)) - betweenness_source = sage_malloc(n*sizeof(numerical_type)) - betweenness = sage_malloc(n*sizeof(numerical_type)) + cdef int layer_current_beginning + cdef int layer_current_end + cdef int layer_next_end + + cdef int source,i,j,u,v + cdef uint32_t * p_tmp if numerical_type is mpq_t: mpq_init(mpq_tmp) + init_short_digraph(g, G, edge_labelled = False) + init_reverse(bfs_dag, g) + + queue = sage_malloc(n*sizeof(uint32_t)) + degrees = sage_malloc(n*sizeof(uint32_t)) + n_paths_from_source = sage_malloc(n*sizeof(numerical_type)) + betweenness_source = sage_malloc(n*sizeof(numerical_type)) + betweenness = sage_malloc(n*sizeof(numerical_type)) + if (queue == NULL or degrees == NULL or n_paths_from_source == NULL or @@ -187,12 +192,8 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): sage_free(betweenness) raise MemoryError - cdef int layer_current_beginning - cdef int layer_current_end - cdef int layer_next_end - - cdef int source,i,j,u,v - cdef uint32_t * p_tmp + bitset_init(seen,n) + bitset_init(next_layer,n) if numerical_type is double: memset(betweenness,0,n*sizeof(double)) @@ -305,15 +306,6 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): mpq_clear(n_paths_from_source[i]) mpq_clear(mpq_tmp) - if not G.is_directed(): - betweenness_list = [x/2 for x in betweenness_list] - - if normalize: - if G.is_directed(): - betweenness_list = [ x/((n-1)*(n-2)) for x in betweenness_list] - else: - betweenness_list = [2*x/((n-1)*(n-2)) for x in betweenness_list] - free_short_digraph(g) free_short_digraph(bfs_dag) bitset_free(seen) @@ -324,4 +316,14 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): sage_free(betweenness_source) sage_free(betweenness) + if not G.is_directed(): + betweenness_list = [x/2 for x in betweenness_list] + + if normalize: + if G.is_directed(): + betweenness_list = [ x/((n-1)*(n-2)) for x in betweenness_list] + else: + betweenness_list = [2*x/((n-1)*(n-2)) for x in betweenness_list] + + return {vv:betweenness_list[i] for i,vv in enumerate(G.vertices())} From 960fdaaa53945a65d11bb86fb34d7e576430b75f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 20:58:50 +0200 Subject: [PATCH 404/665] trac #18262: increase identation (and nothing else) --- src/sage/graphs/centrality.pyx | 274 ++++++++++++++++----------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 0bc9406b386..0976e4cfe8c 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -171,150 +171,150 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): if numerical_type is mpq_t: mpq_init(mpq_tmp) - init_short_digraph(g, G, edge_labelled = False) - init_reverse(bfs_dag, g) - - queue = sage_malloc(n*sizeof(uint32_t)) - degrees = sage_malloc(n*sizeof(uint32_t)) - n_paths_from_source = sage_malloc(n*sizeof(numerical_type)) - betweenness_source = sage_malloc(n*sizeof(numerical_type)) - betweenness = sage_malloc(n*sizeof(numerical_type)) - - if (queue == NULL or - degrees == NULL or - n_paths_from_source == NULL or - betweenness_source == NULL or - betweenness == NULL): - sage_free(queue) - sage_free(n_paths_from_source) - sage_free(degrees) - sage_free(betweenness_source) - sage_free(betweenness) - raise MemoryError - - bitset_init(seen,n) - bitset_init(next_layer,n) - - if numerical_type is double: - memset(betweenness,0,n*sizeof(double)) - else: - for i in range(n): - mpq_init(betweenness[i]) - mpq_set_ui(betweenness[i],0,1) - mpq_init(betweenness_source[i]) - mpq_init(n_paths_from_source[i]) - - for source in range(n): + init_short_digraph(g, G, edge_labelled = False) + init_reverse(bfs_dag, g) + + queue = sage_malloc(n*sizeof(uint32_t)) + degrees = sage_malloc(n*sizeof(uint32_t)) + n_paths_from_source = sage_malloc(n*sizeof(numerical_type)) + betweenness_source = sage_malloc(n*sizeof(numerical_type)) + betweenness = sage_malloc(n*sizeof(numerical_type)) + + if (queue == NULL or + degrees == NULL or + n_paths_from_source == NULL or + betweenness_source == NULL or + betweenness == NULL): + sage_free(queue) + sage_free(n_paths_from_source) + sage_free(degrees) + sage_free(betweenness_source) + sage_free(betweenness) + raise MemoryError + + bitset_init(seen,n) + bitset_init(next_layer,n) if numerical_type is double: - memset(betweenness_source ,0,n*sizeof(double)) - memset(n_paths_from_source,0,n*sizeof(double)) - n_paths_from_source[source]=1 + memset(betweenness,0,n*sizeof(double)) else: for i in range(n): - mpq_set_ui(betweenness_source[i] ,0,1) - mpq_set_ui(n_paths_from_source[i],0,1) - mpq_set_ui(n_paths_from_source[source],1,1) - - # initialize data - bitset_set_first_n(seen, 0) - bitset_add(seen,source) - bitset_set_first_n(next_layer, 0) - - memset(degrees,0,n*sizeof(uint32_t)) - - queue[0] = source - layer_current_beginning = 0 - layer_current_end = 1 - layer_next_end = 1 - - # The number of shortest paths from 'source' to every other vertex. - # - # It is a BFS. The graph is explored layer by layer. - while layer_current_beginning (betweenness_list[i])).set_from_mpq(betweenness[i]) - for i in range(n): - mpq_clear(betweenness_source[i]) - mpq_clear(betweenness[i]) - mpq_clear(n_paths_from_source[i]) - mpq_clear(mpq_tmp) - - free_short_digraph(g) - free_short_digraph(bfs_dag) - bitset_free(seen) - bitset_free(next_layer) - sage_free(queue) - sage_free(n_paths_from_source) - sage_free(degrees) - sage_free(betweenness_source) - sage_free(betweenness) + if numerical_type is double: + betweenness_list = [betweenness[i] for i in range(n)] + else: + betweenness_list = [Rational(None) for x in range(n)] + + for i in range(n): + ( (betweenness_list[i])).set_from_mpq(betweenness[i]) + for i in range(n): + mpq_clear(betweenness_source[i]) + mpq_clear(betweenness[i]) + mpq_clear(n_paths_from_source[i]) + mpq_clear(mpq_tmp) + + free_short_digraph(g) + free_short_digraph(bfs_dag) + bitset_free(seen) + bitset_free(next_layer) + sage_free(queue) + sage_free(n_paths_from_source) + sage_free(degrees) + sage_free(betweenness_source) + sage_free(betweenness) if not G.is_directed(): betweenness_list = [x/2 for x in betweenness_list] From a8c015933b1e3f3bd8b316829f1a9df0c3a95676 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 21:02:44 +0200 Subject: [PATCH 405/665] trac #18262: Exception check --- src/sage/graphs/centrality.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 0976e4cfe8c..56a84185375 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -171,6 +171,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): if numerical_type is mpq_t: mpq_init(mpq_tmp) + try: init_short_digraph(g, G, edge_labelled = False) init_reverse(bfs_dag, g) @@ -293,6 +294,8 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): else: mpq_add(betweenness[i],betweenness[i],betweenness_source[i]) + sig_check() # check for KeyboardInterrupt + if numerical_type is double: betweenness_list = [betweenness[i] for i in range(n)] else: @@ -306,6 +309,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): mpq_clear(n_paths_from_source[i]) mpq_clear(mpq_tmp) + finally: free_short_digraph(g) free_short_digraph(bfs_dag) bitset_free(seen) From d665ec7dc38353a36ef6212db70cf25ccde97bc3 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 20 Apr 2015 21:04:59 +0200 Subject: [PATCH 406/665] trac #18262: Simplify memory allocation --- src/sage/graphs/centrality.pyx | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 56a84185375..5dfb44cdbbc 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -20,6 +20,7 @@ from sage.graphs.base.static_sparse_graph cimport * from libc.stdint cimport uint32_t from sage.libs.gmp.mpq cimport * from sage.rings.rational cimport Rational +from sage.ext.memory cimport check_malloc, check_calloc ctypedef fused numerical_type: mpq_t @@ -175,23 +176,11 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): init_short_digraph(g, G, edge_labelled = False) init_reverse(bfs_dag, g) - queue = sage_malloc(n*sizeof(uint32_t)) - degrees = sage_malloc(n*sizeof(uint32_t)) - n_paths_from_source = sage_malloc(n*sizeof(numerical_type)) - betweenness_source = sage_malloc(n*sizeof(numerical_type)) - betweenness = sage_malloc(n*sizeof(numerical_type)) - - if (queue == NULL or - degrees == NULL or - n_paths_from_source == NULL or - betweenness_source == NULL or - betweenness == NULL): - sage_free(queue) - sage_free(n_paths_from_source) - sage_free(degrees) - sage_free(betweenness_source) - sage_free(betweenness) - raise MemoryError + queue = check_malloc(n*sizeof(uint32_t)) + degrees = check_malloc(n*sizeof(uint32_t)) + n_paths_from_source = check_malloc(n*sizeof(numerical_type)) + betweenness_source = check_malloc(n*sizeof(numerical_type)) + betweenness = check_malloc(n*sizeof(numerical_type)) bitset_init(seen,n) bitset_init(next_layer,n) From 00012b09a7f6b76ce03d574f9c4caf6d7edc55b1 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Mon, 20 Apr 2015 12:36:04 -0700 Subject: [PATCH 407/665] doc revision --- .../root_system/integrable_representations.py | 135 +++++++++++------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 514520e71c5..c91cfe489ff 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -32,10 +32,6 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): - ``Lam`` -- a dominant weight in an extended weight lattice of affine type - OPTIONAL: - - - ``depth`` -- a parameter indicating how far to push computations - REFERENCES: .. [Kac] Kac, *Infinite-dimensional Lie algebras*, Third Edition. @@ -49,24 +45,36 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): functions and modular forms. Adv. in Math. 53 (1984), no. 2, 125-264. If `\Lambda` is a dominant integral weight for an affine root system, - there exists a unique integrable representation of highest weight - `\Lambda`. If `\mu` is another weight such that `\Lambda - \mu` is in - the root lattice, then multiplicity of `\mu` in this representation will - be denoted `m(\mu)`. - - Let `\delta` be the nullroot. Then for fixed `\mu` the function - `m(\mu - k\delta)` is a monotone increasing function of `\mu`. It is - useful to take `\mu` to be such that this function is nonzero if and - only if `k \geq 0`. Therefore we make the following definition. - If `\mu` is such that `m(\mu) \neq 0` but `m(\mu + \delta) = 0` - then `\mu` is called *maximal*. + there exists a unique integrable representation `V=V_\Lambda` of highest weight + `\Lambda`. If `\mu` is another weight, let `m(\mu)` denote the + multiplicity of the weight `\mu` in this representation. The set + `\text{supp}(V)` of `\mu` such that `m(\mu)>0` is contained in the + paraboloid + + .. MATH:: + (\Lambda+\rho|\Lambda+\rho) - (\mu+\rho|\mu+\rho) \ge 0 + + where `(\,|\,)` is the invariant inner product on the weight + lattice and `\rho` is the Weyl vector. Moreover every `\mu` differs from + `\Lambda` by an element of the root lattice. ([Kac], Propositions 11.3 and + 11.4) such that `\Lambda - \mu` is in the root lattice, then multiplicity + of `\mu` in this representation will be denoted `m(\mu)`. The set of `\mu` + such that the multiplicity + + Let `\delta` be the nullroot, which is the lowest positive imaginary + root. Then by [Kac], Proposition 11.3 or Corollary 11.9, for fixed `\mu` + the function `m(\mu - k\delta)` is a monotone increasing function of + `k`. It is useful to take `\mu` to be such that this function is nonzero + if and only if `k \geq 0`. Therefore we make the following definition. If + `\mu` is such that `m(\mu) \neq 0` but `m(\mu + \delta) = 0` then `\mu` is + called *maximal*. Since `\delta` is fixed under the action of the affine Weyl group, and since the weight multiplicities are Weyl group invariant, the - *string function* `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` - is replaced by an equivalent weight. Therefore in tabulating the - string functions, we may assume that `\mu` is dominant. There are - only a finite number of dominant maximal weights. + function `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` is replaced by + an equivalent weight. Therefore in tabulating these functions, we may + assume that `\mu` is dominant. There are only a finite number of dominant + maximal weights. Since every nonzero weight multiplicity appears in the string `\mu - k\delta` for one of the finite number of dominant maximal @@ -93,8 +101,8 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, and we determine their string functions. - It was shown by Kac and Peterson that each string function is the - set of Fourier coefficients of a modular form. + It was shown in [KacPeterson] that each string is the set of Fourier + coefficients of a modular form. Every weight `\mu` such that the weight multiplicity `m(\mu)` is nonzero has the form @@ -248,7 +256,13 @@ def rho(self): def level(self): """ - The level of the representation equals `(\\rho|\delta)`. See [Kac] section 12.4. + The level of the representation equals `(\Lambda|\delta)`. See [Kac] section 12.4. + + EXAMPLES:: + + sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: [IntegrableRepresentation(Lambda[i]).level() for i in [0,1,2]] + [1, 1, 2] """ return ZZ(self._inner_pq(self._Lam, self._delta)) @@ -395,7 +409,7 @@ def to_weight(self, n): Returns the weight associated to the tuple ``n``. If ``n`` is the tuple `(n_1, n_2, \ldots)`, then the associated - weight is `\Lambda - sum_i n_i \alpha_i`, where `\Lambda` + weight is `\Lambda - \sum_i n_i \\alpha_i`, where `\Lambda` is the weight of the representation. EXAMPLES:: @@ -460,6 +474,13 @@ def s(self, n, i): """ Implements the `i`-th simple reflection in the internal representation of weights by tuples. + + EXAMPLES:: + + sage: v = IntegrableRepresentation(RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: [v.s((0,0,0),i) for i in v._index_set] + [(1, 0, 0), (0, 0, 0), (0, 0, 0)] + """ ret = list(n) # This makes a copy ret[i] += self._Lam._monomial_coefficients.get(i, ZZ.zero()) @@ -469,6 +490,15 @@ def s(self, n, i): def to_dominant(self, n): """ Return the dominant weight equivalent to ``n`` under the affine Weyl group. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(3*Lambda[0]) + sage: n = v.to_dominant((13,11,7)); n + (4, 3, 3) + sage: v.to_weight(n) + Lambda[0] + Lambda[1] + Lambda[2] - 4*delta """ if n in self._ddict: return self._ddict[n] @@ -508,7 +538,7 @@ def to_dominant(self, n): def _freudenthal_roots_imaginary(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of imaginary - roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. + roots `\alpha \in \Delta^+` such that `\\nu - \alpha \in Q^+`. """ l = self._from_weight_helper(nu) kp = min(floor(l[i] / self._a[i]) for i in self._index_set) @@ -518,7 +548,7 @@ def _freudenthal_roots_imaginary(self, nu): def _freudenthal_roots_real(self, nu): r""" It is assumed that ``nu`` is in `Q`. Returns the set of real positive - roots `\alpha \in \Delta^+` such that `\nu - \alpha \in Q^+`. + roots `\alpha \in \Delta^+` such that `\\nu - \alpha \in Q^+`. """ ret = [] for al in self._classical_positive_roots: @@ -529,20 +559,6 @@ def _freudenthal_roots_real(self, nu): ret.append(al+ir) return ret - def freudenthal_roots(self, nu): - r""" - It is assumed that ``nu`` is in `Q`. Returns the set of real roots - `\alpha \in \Delta^+` such that `nu - \alpha \in Q^+`. - - This code is not called in the main algorithm. - """ - ret = [] - for alpha in self._freudenthal_roots_imaginary(nu): - ret.append(alpha) - for alpha in self._freudenthal_roots_real(nu): - ret.append(alpha) - return ret - def _freudenthal_accum(self, nu, al): """ Helper method for computing the Freudenthal formula. @@ -590,7 +606,7 @@ def m(self, n): """ INPUT: - - ``n`` -- a representing a weight `\mu`. + - ``n`` -- a tuple representing a weight `\mu`. Return the multiplicity of the weight `\mu` in ``self``, where `\mu = \Lambda - \sum_i n_i \\alpha_i`. @@ -624,7 +640,7 @@ def m(self, n): print "m: error - failed to compute m%s"%n.__repr__() return ret - def dominant_maximal(self): + def dominant_maximal_weights(self): """ A weight `\\mu` is *maximal* if it has nonzero multiplicity but `\\mu+\\delta`` has multiplicity zero. There are a finite number @@ -634,8 +650,17 @@ def dominant_maximal(self): alcove and `k` is the level. The construction used in this method is based on that Proposition. - + EXAMPLES:: + sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights() + [2*Lambda[0], + Lambda[0] + Lambda[2] - delta, + 2*Lambda[1] - delta, + Lambda[1] + Lambda[3] - 2*delta, + 2*Lambda[2] - 2*delta, + 2*Lambda[3] - 3*delta] + """ k = self.level() Lambda = self._P.fundamental_weights() @@ -690,19 +715,15 @@ def strings(self, depth=12): 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ - for max_weight in self.dominant_maximal(): + for max_weight in self.dominant_maximal_weights(): s = self.string(max_weight, depth) print "%s:"%max_weight, for j in s: print j, print - def modular_characteristic(self, n=None): + def modular_characteristic(self, mu=None): """ - OPTIONAL: - - - ``mu`` -- - The modular characteristic is a rational number introduced by Kac and Peterson (1984), required to interpret the string functions as Fourier coefficients of modular forms. See @@ -721,13 +742,25 @@ def modular_characteristic(self, n=None): OPTIONAL: + - ``mu`` -- a weight; or alternatively: - ``n`` -- a tuple representing a weight `\mu`. - The weight `\mu` is `\Lambda - \sum_i n_i \\alpha_i`. The function - returns `m_\Lambda` if `n` is omitted, otherwise it returns - `m_{\Lambda,\mu}`. + If not optional parameter is specified, The function returns `m_\Lambda`. + If ``mu`` is specified, it returns `m_{\Lambda,\mu}`. You may use the + tuple ``n`` to specify `\mu`. If you do this, `\mu` is + `\Lambda - \sum_i n_i \\alpha_i`. + EXAMPLES:: + + sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(3*Lambda[0]+2*Lambda[1]) + sage: [v.modular_characteristic(x) for x in v.dominant_maximal_weights()] + [11/56, -1/280, 111/280] """ + if type(mu) is tuple: + n = mu + else: + n = self.from_weight(mu) k = self.level() hd = self._dual_coxeter_number m_Lambda = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho)/(2*(k+hd)) - \ From a190d1f1f16ccab76ac2812c5b9a923ed6ff3e9c Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 20 Apr 2015 22:51:14 +0200 Subject: [PATCH 408/665] some weasel words I feel uncomfortable without --- src/sage/combinat/ordered_tree.py | 47 +++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index d358beff776..639893c6c4b 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -526,8 +526,8 @@ def left_right_symmetry(self): def sort_key(self): """ - Return a tuple of nonnegative integers encoding the tree - ``self``. + Return a tuple of nonnegative integers encoding the ordered + tree ``self``. The first entry of the tuple is the number of children of the root. Then the rest of the tuple is the concatenation of the @@ -538,10 +538,32 @@ def sort_key(self): .. NOTE:: - On the :class:`LabelledOrderedTree` subclass, this method - is overridden by a slightly different method, which encodes - not only the numbers of children of the nodes of ``self``, - but also their labels. + By default, this method does not encode any extra + structure that ``self`` might have -- e.g., if you were + to define a class ``EdgeColoredOrderedTree`` which + implements edge-colored trees and which inherits from + :class:`OrderedTree`, then the :meth:`sort_key` method + it would inherit would forget about the colors of the + edges (and thus would not characterize edge-colored + trees uniquely). If you want to preserve extra data, + you need to override this method or use a new method. + For instance, on the :class:`LabelledOrderedTree` + subclass, this method is overridden by a slightly + different method, which encodes not only the numbers + of children of the nodes of ``self``, but also their + labels. + Be careful with using overridden methods, however: + If you have (say) a class ``BalancedTree`` which + inherits from :class:`OrderedTree` and which encodes + balanced trees, and if you have another class + ``BalancedLabelledOrderedTree`` which inherits both + from ``BalancedOrderedTree`` and from + :class:`LabelledOrderedTree`, then (depending on the MRO) + the default :meth:`sort_key` method on + ``BalancedLabelledOrderedTree`` (unless manually + overridden) will be taken either from ``BalancedTree`` + or from :class:`LabelledOrderedTree`, and in the former + case will ignore the labelling! EXAMPLES:: @@ -1199,6 +1221,19 @@ def sort_key(self): be used to sort the labelled ordered trees provided that the labels belong to a type which is totally ordered. + .. WARNING:: + + This method overrides :meth:`OrderedTree.sort_key` + and returns a result different from what the latter + would return, as it wants to encode the whole labelled + tree including its labelling rather than just the + unlabelled tree. Therefore, be careful with using this + method on subclasses of :class:`LabelledOrderedTree`; + under some circumstances they could inherit it from + another superclass instead of from :class:`OrderedTree`, + which would cause the method to forget the labelling. + See the docstring of :meth:`OrderedTree.sort_key`. + EXAMPLES:: sage: L2 = LabelledOrderedTree([], label=2) From 99f6de56e5d8bc4b834d4d22abb0303560103b32 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 20 Apr 2015 23:18:33 +0200 Subject: [PATCH 409/665] review patch --- src/sage/combinat/ordered_tree.py | 6 +- src/sage/combinat/rooted_tree.py | 104 +++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 639893c6c4b..eec818660f2 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -531,7 +531,8 @@ def sort_key(self): The first entry of the tuple is the number of children of the root. Then the rest of the tuple is the concatenation of the - tuples associated to subtrees from left to right. + tuples associated to these children (we view the children of + a tree as trees themselves) from left to right. This tuple characterizes the tree uniquely, and can be used to sort the ordered trees. @@ -1215,7 +1216,8 @@ def sort_key(self): The first entry of the tuple is a pair consisting of the number of children of the root and the label of the root. Then the rest of the tuple is the concatenation of the tuples - associated to subtrees from left to right. + associated to these children (we view the children of + a tree as trees themselves) from left to right. This tuple characterizes the labelled tree uniquely, and can be used to sort the labelled ordered trees provided that the diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 6a56d094b39..c28a0b06fe1 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -95,6 +95,29 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList): sage: RT = RootedTrees() sage: from_hexacode('32001010', RT) [[[]], [[]], [[], []]] + + .. NOTE:: + + Unlike an ordered tree, an (unordered) rooted tree is a + multiset (rather than a list) of children. That is, two + ordered trees which differ from each other by switching + the order of children are equal to each other as (unordered) + rooted trees. Internally, rooted trees are encoded as + :class:`sage.structure.list_clone.NormalizedClonableList` + instances, and instead of storing their children as an + actual multiset, they store their children as a list which + is sorted according to their :meth:`sort_key` value. This + is as good as storing them as multisets, since the + :meth:`sort_key` values are sortable and distinguish + different (unordered) trees. However, if you wish to define + a subclass of :class:`RootedTree` which implements rooted + trees with extra structure (say, a class of edge-colored + rooted trees, or a class of rooted trees with a cyclic + order on the list of children), then the inherited + :meth:`sort_key` method will no longer distinguish different + trees (and, as a consequence, equal trees will be regarded + as distinct). Thus, you will have to override the method by + one that does distinguish different trees. """ # Standard auto-parent trick __metaclass__ = ClasscallMetaclass @@ -176,15 +199,39 @@ def __init__(self, parent=None, children=[], check=True): def sort_key(self): """ - Return a tuple of numbers that can be used to sort the rooted trees. + Return a tuple of nonnegative integers encoding the rooted + tree ``self``. + + The first entry of the tuple is the number of children of the + root. Then the rest of the tuple is obtained as follows: List + the tuples corresponding to all children (we are regarding the + children themselves as trees). Order this list (not the + tuples!) in lexicographically increasing order, and flatten + it into a single tuple. - This tuple is in fact an encoding of the tree. The values are - the valences of the vertices. The first value is the valence of the - root. Then the rest of the tuple is the concatenation of the tuples - associated to subtrees. + This tuple characterizes the rooted tree uniquely, and can be + used to sort the rooted trees. + + .. NOTE:: + + The tree ``self`` must be normalized before calling this + method (see :meth:`normalize`). This doesn't matter + unless you are inside the :meth:`clone` context manager, + because outside of it every rooted tree is already + normalized. + + .. NOTE:: - The tree ``self`` must be normalized before calling this, meaning - that it subtrees have to be sorted according to their sort key. + By default, this method does not encode any extra + structure that ``self`` might have. If you have a subclass + inheriting from :class:`RootedTree` which allows for some + extra structure, you need to override :meth:`sort_key` in + order to preserve this structure (for example, the + :class:`LabelledRootedTree` class does this in + :meth:`LabelledRootedTree.sort_key`). See the note in the + docstring of + :meth:`sage.combinat.ordered_tree.OrderedTree.sort_key` + for a pitfall. EXAMPLES:: @@ -241,6 +288,8 @@ def normalize(self): sage: rt2 = RT([[[]],[]]) sage: rt1 is rt2 False + sage: rt1 == rt2 + True sage: rt1._get_list() == rt2._get_list() True """ @@ -771,17 +820,42 @@ def _auto_parent(cls): def sort_key(self): """ - Return a tuple that can be used to sort the labelled rooted trees. + Return a tuple of nonnegative integers encoding the labelled + rooted tree ``self``. + + The first entry of the tuple is a pair consisting of the + number of children of the root and the label of the root. Then + the rest of the tuple is obtained as follows: List + the tuples corresponding to all children (we are regarding the + children themselves as trees). Order this list (not the + tuples!) in lexicographically increasing order, and flatten + it into a single tuple. + + This tuple characterizes the labelled rooted tree uniquely, and + can be used to sort the labelled rooted trees provided that the + labels belong to a type which is totally ordered. - Each term is a pair (valence, label). + .. NOTE:: + + The tree ``self`` must be normalized before calling this + method (see :meth:`normalize`). This doesn't matter + unless you are inside the :meth:`clone` context manager, + because outside of it every rooted tree is already + normalized. - This tuple is in fact an encoding of the tree. The values are - the valences and labels of the vertices. The first value is - the valence of the root. Then the rest of the tuple is the - concatenation of the tuples associated to subtrees. + .. NOTE:: - The tree ``self`` must be normalized before calling this, meaning - that it subtrees have to be sorted according to their sort key. + This method overrides :meth:`RootedTree.sort_key` + and returns a result different from what the latter + would return, as it wants to encode the whole labelled + tree including its labelling rather than just the + unlabelled tree. Therefore, be careful with using this + method on subclasses of :class:`RootedOrderedTree`; + under some circumstances they could inherit it from + another superclass instead of from :class:`RootedTree`, + which would cause the method to forget the labelling. + See the docstrings of :meth:`RootedTree.sort_key` and + :meth:`sage.combinat.ordered_tree.OrderedTree.sort_key`. EXAMPLES:: From dc0ebfeb5a185b5a1ab3bedfbe2f786ca6de0965 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Mon, 20 Apr 2015 23:26:34 +0200 Subject: [PATCH 410/665] also improve the doc of left_right_symmetry --- src/sage/combinat/ordered_tree.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index eec818660f2..1d449bd05cc 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -509,7 +509,14 @@ def to_poset(self, root_to_leaf=False): @combinatorial_map(order=2, name="Left-right symmetry") def left_right_symmetry(self): r""" - Return the symmetric tree of ``self`` + Return the symmetric tree of ``self``. + + The symmetric tree `s(T)` of an ordered tree `T` is + defined as follows: + If `T` is an ordered tree with children `C_1, C_2, \ldots, C_k` + (listed from left to right), then the symmetric tree `s(T)` of + `T` is the ordered tree with children + `s(C_k), s(C_{k-1}), \ldots, s(C_1)` (from left to right). EXAMPLES:: @@ -1189,7 +1196,26 @@ def _auto_parent(cls): @combinatorial_map(order=2, name="Left-right symmetry") def left_right_symmetry(self): r""" - Return the symmetric tree of ``self`` + Return the symmetric tree of ``self``. + + The symmetric tree `s(T)` of a labelled ordered tree `T` is + defined as follows: + If `T` is a labelled ordered tree with children + `C_1, C_2, \ldots, C_k` (listed from left to right), then the + symmetric tree `s(T)` of `T` is a labelled ordered tree with + children `s(C_k), s(C_{k-1}), \ldots, s(C_1)` (from left to + right), and with the same root label as `T`. + + .. NOTE:: + + If you have a subclass of :meth:`LabelledOrderedTree` + which also inherits from another subclass of + :meth:`OrderedTree` which does not come with a labelling, + then (depending on the method resolution order) it might + happen that this method gets overridden by an + implementation from that other subclass, and thus forgets + about the labels. In this case you need to manually + override this method on your subclass. EXAMPLES:: From f7824807234b262f84e004d007f536593569df1e Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Mon, 20 Apr 2015 17:21:05 -0700 Subject: [PATCH 411/665] branching rules --- .../root_system/integrable_representations.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index c91cfe489ff..79c79a44937 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -21,6 +21,7 @@ from sage.matrix.constructor import Matrix from sage.functions.other import floor from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet +import sage.combinat.root_system.weyl_characters # TODO: Make this a proper parent and implement actions class IntegrableRepresentation(CategoryObject, UniqueRepresentation): @@ -770,3 +771,59 @@ def modular_characteristic(self, mu=None): else: mu = self.to_weight(n) return m_Lambda-self._inner_pp(mu,mu)/(2*k) + + def branch(self, wcring, depth): + """ + If ``self`` is a representation of the untwisted affine Lie algebra of Cartan + type ``[X, r, 1]``, then corresponding to the inclusion of ``[X, r]`` in + ``[X, r, 1]``, there is a branching rule producing a sequence of representations + of type ``[X, r]``. The `k`-th representation of this sequence is the restriction + of all weights in which `\delta` has coefficient `k`. + + INPUT: + + - ``wcring`` -- a WeylCharacterRing of Cartan Type `[X, r]` + - ``depth`` -- an upper bound for `k` determining how many terms to give. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[0]) + sage: A2 = WeylCharacterRing("A2",style="coroots") + sage: v.branch(A2, 5) + [A2(0,0), + A2(1,1), + A2(0,0) + 2*A2(1,1) + A2(2,2), + 2*A2(0,0) + 2*A2(0,3) + 4*A2(1,1) + 2*A2(3,0) + 2*A2(2,2), + 4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1), + 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] + + """ + def next_level(x): + ret = [] + for i in self._index_set: + t = list(x[0]) + t[i] += 1 + t = tuple(t) + u = self.to_weight(t) + m = self.m(t) + if m > 0 and t[0] <= depth: + ret.append((t,m)) + return ret + hwv = (tuple([0 for i in self._index_set]), 1) + terms = RecursivelyEnumeratedSet([hwv], next_level) + fw = wcring.fundamental_weights() + P = self.weight_lattice() + ret = [] + for l in range(depth+1): + lterms = [x for x in terms if x[0][0] == l] + ldict = {} + for x in lterms: + mc = P(self.to_weight(x[0])).monomial_coefficients() + contr = sum(fw[i]*mc.get(i,0) for i in self._index_set_classical).coerce_to_sl() + if ldict.has_key(contr): + ldict[contr] += x[1] + else: + ldict[contr] = x[1] + ret.append(wcring.char_from_weights(ldict)) + return ret From 54336b9146a247b6ee7ae97e47d07e0a5d5c41d0 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Mon, 20 Apr 2015 21:17:44 -0400 Subject: [PATCH 412/665] add coercion from s to H/Ht because coercion was passing through h and p bases --- src/sage/combinat/sf/macdonald.py | 63 +++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 3bcb16f1ca7..094af9682e2 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1185,6 +1185,59 @@ def _to_s(self, part): class Element(MacdonaldPolynomials_generic.Element): pass +def self_to_s(self, x): + r""" + Convert an element of either the ``H`` or ``Ht`` basis to the Schur basis + + This function is here to force the coercion path to the Schur basis. + + INPUT: + + - ``self`` - either a ``H`` or an ``Ht`` Macdonald basis + - ``x`` - an element of ``self`` + + OUTPUT: + + - an element of the Schur basis + + EXAMPLES:: + + sage: Ht = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().Ht() + sage: sage.combinat.sf.macdonald.self_to_s(Ht, Ht[2,1]) + q*t*s[1, 1, 1] + (q+t)*s[2, 1] + s[3] + sage: H = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().H() + sage: sage.combinat.sf.macdonald.self_to_s(H, H[2,1]) + q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3] + """ + return self._s(self._self_to_m(x)) + +def s_to_self( self, x ): + r""" + Convert an element of either the Schur basis to either the ``H`` or ``Ht`` basis + + This function is here to force the coercion path from the Schur basis. + + INPUT: + + - ``self`` - either a ``H`` or an ``Ht`` Macdonald basis + - ``x`` - an element of ``s`` basis + + OUTPUT: + + - an element of the basis ``self`` + + EXAMPLES:: + sage: s = SymmetricFunctions(FractionField(QQ['q','t'])).s() + sage: Ht = s.symmetric_function_ring().macdonald().Ht() + sage: sage.combinat.sf.macdonald.s_to_self(Ht, s[2]) + ((-q)/(-q+t))*McdHt[1, 1] + (t/(-q+t))*McdHt[2] + sage: H = s.symmetric_function_ring().macdonald().H() + sage: sage.combinat.sf.macdonald.s_to_self(H, s[2]) + (q/(q*t-1))*McdH[1, 1] - (1/(q*t-1))*McdH[2] + """ + return self._m_to_self(self._m(x)) + + class MacdonaldPolynomials_h(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" @@ -1211,9 +1264,14 @@ def __init__(self, macdonald): self._m = self._sym.m() self._Lmunu = macdonald.Ht()._Lmunu category = ModulesWithBasis(self.base_ring()) + self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) + self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) + _self_to_s = self_to_s + _s_to_self = s_to_self + def _self_to_m(self, x): r""" Return an element ``x`` of ``self`` expanded in the monomial basis. @@ -1334,9 +1392,14 @@ def __init__(self, macdonald): self._self_to_m_cache = _ht_to_m_cache self._m = self._sym.m() category = ModulesWithBasis(self.base_ring()) + self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) + self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) + _self_to_s = self_to_s + _s_to_self = s_to_self + def _Lmunu(self, nu, mu ): r""" Return the coefficient of `m_\nu` in `{\tilde H}_\mu`. From 0a6d27c189dc0d592dc49984588cc457204c5bed Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Mon, 20 Apr 2015 19:43:10 -0700 Subject: [PATCH 413/665] check cartan type of weyl character ring --- .../combinat/root_system/integrable_representations.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 79c79a44937..0c0f7fd394c 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -304,6 +304,12 @@ def __repr__(self): """ return "The Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) + def cartan_type(self): + """ + Return the Cartan Type of ``self``. + """ + return self._cartan_type + def _inner_qq(self, qelt1, qelt2): """ Symmetric form between two elements of the root lattice. @@ -799,6 +805,8 @@ def branch(self, wcring, depth): 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] """ + if wcring.cartan_type() != self.cartan_type().classical(): + raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) def next_level(x): ret = [] for i in self._index_set: From 34e9d383550f31889ccbdddae6e93928bf66b271 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Tue, 21 Apr 2015 10:03:07 +0200 Subject: [PATCH 414/665] trac #17750: Remove unreliable doctest --- src/sage/graphs/genus.pyx | 41 ++++++--------------------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/src/sage/graphs/genus.pyx b/src/sage/graphs/genus.pyx index b2b04ec6dbc..7aec64fa436 100644 --- a/src/sage/graphs/genus.pyx +++ b/src/sage/graphs/genus.pyx @@ -115,51 +115,22 @@ cdef class simple_connected_genus_backtracker: def __dealloc__(self): """ - Deallocate the simple_connected_genus_backtracker object. - - TEST:: - - sage: import sage.graphs.genus - sage: import gc - sage: G = graphs.CompleteGraph(100) - sage: G = Graph(G, implementation='c_graph', sparse=False) - sage: gc.collect() # random - 54 - sage: t = get_memory_usage() - sage: for i in xrange(1000): - ... gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) - ... gb = None #indirect doctest - ... - sage: gc.collect() - 0 - sage: get_memory_usage(t) <= 0.0 - True """ cdef int i if self.vertex_darts != NULL: - if self.vertex_darts[0] != NULL: - sage_free(self.vertex_darts[0]) + sage_free(self.vertex_darts[0]) sage_free(self.vertex_darts) if self.swappers != NULL: - if self.swappers[0] != NULL: - sage_free(self.swappers[0]) + sage_free(self.swappers[0]) sage_free(self.swappers) - if self.face_map != NULL: - sage_free(self.face_map) - - if self.visited != NULL: - sage_free(self.visited) - - if self.face_freeze != NULL: - sage_free(self.face_freeze) - - if self.degree != NULL: - sage_free(self.degree) - + sage_free(self.face_map) + sage_free(self.visited) + sage_free(self.face_freeze) + sage_free(self.degree) cdef int got_memory(self): """ From 77e38d28e608521c7a79decf16bfb3f09b089737 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 21 Apr 2015 10:51:34 +0200 Subject: [PATCH 415/665] Define 3-argument version Py_VISIT3 of Py_VISIT --- src/sage/ext/pyx_visit.h | 6 ++--- src/sage/structure/coerce_dict.pyx | 41 +++++++----------------------- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/sage/ext/pyx_visit.h b/src/sage/ext/pyx_visit.h index 49bbe7328b7..2dd1fd125b1 100644 --- a/src/sage/ext/pyx_visit.h +++ b/src/sage/ext/pyx_visit.h @@ -1,9 +1,9 @@ -/* Cython-compatible version of Py_VISIT */ +/* 3-argument version of Py_VISIT, easier to use from Cython */ -#define Pyx_VISIT(op) \ +#define Py_VISIT3(op, visit, arg) \ do { \ if (op) { \ - int vret = __pyx_v_visit((PyObject *)(op), __pyx_v_arg); \ + int vret = visit((PyObject *)(op), arg); \ if (vret) \ return vret; \ } \ diff --git a/src/sage/structure/coerce_dict.pyx b/src/sage/structure/coerce_dict.pyx index 9645dc9d3da..49d548362f4 100644 --- a/src/sage/structure/coerce_dict.pyx +++ b/src/sage/structure/coerce_dict.pyx @@ -68,30 +68,7 @@ cdef extern from "Python.h": int PyList_SetItem(object list, Py_ssize_t index, PyObject * item) except -1 cdef extern from "pyx_visit.h": - void Pyx_VISIT(PyObject*) - -#this serves no purpose here anymore. Perhaps elsewhere? -cpdef inline Py_ssize_t signed_id(x): - """ - A function like Python's :func:`id` returning *signed* integers, - which are guaranteed to fit in a ``Py_ssize_t``. - - Theoretically, there is no guarantee that two different Python - objects have different ``signed_id()`` values. However, under the - mild assumption that a C pointer fits in a ``Py_ssize_t``, this - is guaranteed. - - TESTS:: - - sage: a = 1.23e45 # some object - sage: from sage.structure.coerce_dict import signed_id - sage: s = signed_id(a) - sage: id(a) == s or id(a) == s + 2**32 or id(a) == s + 2**64 - True - sage: signed_id(a) <= sys.maxsize - True - """ - return (x) + void Py_VISIT3(PyObject*, visitproc, void* arg) #it's important that this is not an interned string: this object #must be a unique sentinel. We could reuse the "dummy" sentinel @@ -845,13 +822,13 @@ cdef class MonoDict: cdef int MonoDict_traverse(MonoDict op, visitproc visit, void *arg): if op.table == NULL: return 0 - Pyx_VISIT(op.eraser) + Py_VISIT3(op.eraser, visit, arg) cdef size_t i for i in range(op.mask + 1): cursor = &op.table[i] if cursor.key_id != NULL and cursor.key_id != dummy: - Pyx_VISIT(cursor.key_weakref) - Pyx_VISIT(cursor.value) + Py_VISIT3(cursor.key_weakref, visit, arg) + Py_VISIT3(cursor.value, visit, arg) return 0 @@ -1557,15 +1534,15 @@ cdef class TripleDict: cdef int TripleDict_traverse(TripleDict op, visitproc visit, void *arg): if op.table == NULL: return 0 - Pyx_VISIT(op.eraser) + Py_VISIT3(op.eraser, visit, arg) cdef size_t i for i in range(op.mask + 1): cursor = &op.table[i] if cursor.key_id1 != NULL and cursor.key_id1 != dummy: - Pyx_VISIT(cursor.key_weakref1) - Pyx_VISIT(cursor.key_weakref2) - Pyx_VISIT(cursor.key_weakref3) - Pyx_VISIT(cursor.value) + Py_VISIT3(cursor.key_weakref1, visit, arg) + Py_VISIT3(cursor.key_weakref2, visit, arg) + Py_VISIT3(cursor.key_weakref3, visit, arg) + Py_VISIT3(cursor.value, visit, arg) return 0 cdef int TripleDict_clear(TripleDict op): From 3f66f35464059da7dc1a3a0a2e4ad494d8052128 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 21 Apr 2015 13:57:08 +0200 Subject: [PATCH 416/665] Abstract class for channels --- src/sage/coding/channel_constructions.py | 265 +++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 src/sage/coding/channel_constructions.py diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py new file mode 100644 index 00000000000..766391a3a3e --- /dev/null +++ b/src/sage/coding/channel_constructions.py @@ -0,0 +1,265 @@ +r""" +Channels + +Given an input space and an output space, a channel takes element from +the input space (the message) and transforms it into an element of the output space +(the transmitted message). + +This file contains the following elements: + + - *AbstractChannel*, the abstract class for Channels + - *ChannelStaticErrorRate*, which creates a specific number of errors in each + transmitted message + - *ChannelErrorErasure*, which creates a specific number of errors and a + specific number of erasures in each transmitted message +""" + +#***************************************************************************** +# Copyright (C) 2015 David Lucas +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.rings.finite_rings.constructor import GF +from sage.misc.prandom import randint, random +from sage.modules.free_module_element import vector +from sage.misc.abstract_method import abstract_method +from sage.combinat.cartesian_product import CartesianProduct +from sage.modules.free_module import VectorSpace + +def _random_error_position(n , number_errors): + r""" + Returns a list of exactly ``number_errors`` random numbers between 0 and ``n-1`` + This is a helper function, for internal use only. + This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + + INPUT: + + - ``number_errors`` -- the number of elements in the list + + - ``n`` -- upper bound for the elements of the list + + OUTPUT: + + - A list of integers + + EXAMPLES:: + + sage: sage.coding.channel_constructions._random_error_position(6, 2) # random + [1, 4] + """ + error_position = [] + i = 0 + while i < n and number_errors > 0: + if random() < number_errors/(n-i): + error_position.append(i) + number_errors -= 1 + i += 1 + return error_position + +def _random_error_vector(n, F, error_positions): + r""" + Return a vector of length ``n`` over ``F`` filled with random non-zero coefficients + at the positions given by ``error_positions``. + This is a helper function, for internal use only. + This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + + INPUT: + + - ``n`` -- the length of the vector + + - ``F`` -- the field over which the vector is defined + + - ``error_positions`` -- the non-zero positions of the vector + + OUTPUT: + + - a vector of ``F`` + + EXAMPLES:: + + sage: sage.coding.channel_constructions._random_error_vector(5, GF(2), [1,3]) + (0, 1, 0, 1, 0) + """ + vect = [F.zero()]*n + for i in error_positions: + while vect[i].is_zero(): + vect[i] = F.random_element() + return vector(F, vect) + +def _tuple_to_integer(value): + r""" + Returns an integer from ``value``. If ``value`` is a tuple, it will return a random + integer between its bounds. + This is a helper function, for internal use only. + + INPUT: + + - ``value`` -- an integer or a couple of integers + + OUTPUT: + + - an integer + + EXAMPLES:: + + sage: sage.coding.channel_constructions._tuple_to_integer(4) + 4 + + sage: sage.coding.channel_constructions._tuple_to_integer((1,5)) # random + 3 + """ + value = value if not hasattr(value, "__iter__") else randint(value[0], value[1]) + return value + + + + + +class AbstractChannel(object): + r""" + Abstract top-class for Channel objects. + + All channel objects must heritate from this class. To implement a channel subclass, one should + do the following: + + - heritate from this class, + + - call the super constructor, + + - override :meth:`transmit_unsafe`. + + While not being mandatory, it might be useful to reimplement representation methods (``__repr__`` and + ``_latex_``), along with a comparison method (``__eq__``). + + This abstract class provides the following parameters: + + - ``input_space`` -- the space of the words to transmit + + - ``output_space`` -- the space of the transmitted words + """ + + def __init__(self, input_space, output_space): + r""" + Initializes parameters for a Channel object. + + This is a private method, which should be called by the constructor + of every encoder, as it automatically initializes the mandatory + parameters of a Channel object. + + INPUT: + + - ``input_space`` -- the space of the words to transmit + + - ``output_space`` -- the space of the transmitted words + + EXAMPLES: + + We first create a new Channel subclass:: + + sage: class ChannelExample(sage.coding.channel_constructions.AbstractChannel): + ....: def __init__(self, input_space, output_space): + ....: super(ChannelExample, self).__init__(input_space, output_space) + + We now create a member of our newly made class:: + + sage: input = VectorSpace(GF(7), 6) + sage: output = VectorSpace(GF(7), 5) + sage: Chan = ChannelExample(input, output) + + We can check its parameters:: + + sage: Chan.input_space() + Vector space of dimension 6 over Finite Field of size 7 + sage: Chan.output_space() + Vector space of dimension 5 over Finite Field of size 7 + """ + self._input_space = input_space + self._output_space = output_space + + def transmit(self, message): + r""" + Returns ``message``, modified accordingly with the algorithm of the channel it was + transmitted through. + Checks if ``message`` belongs to the input space, and returns an exception if not. + + INPUT: + + - ``message`` -- a vector + + OUTPUT: + + - a vector of the output space of ``self`` + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: msg = F((4, 8, 15, 16, 23, 42)) + sage: Chan.transmit(msg) # random + (4, 14, 15, 16, 17, 42) + + If we transmit a vector which is not in the input space of ``self``:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: msg = (4, 8, 15, 16, 23, 42) + sage: Chan.transmit(msg) + Traceback (most recent call last): + ... + TypeError: Message must be an element of the input space for the given channel + """ + if message in self.input_space(): + return self.transmit_unsafe(message) + else : + raise TypeError("Message must be an element of the input space for the given channel") + + def input_space(self): + r""" + Returns the input space of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan.input_space() + Vector space of dimension 6 over Finite Field of size 59 + + """ + return self._input_space + + def output_space(self): + r""" + Returns the output space of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan.output_space() + Vector space of dimension 6 over Finite Field of size 59 + """ + return self._output_space + + @abstract_method + def transmit_unsafe(self, message): + r""" + Returns ``message``, modified accordingly with the algorithm of the channel it was + transmitted through. + This method does not check if ``message`` belongs to the input space of``self``. + + This is an abstract method which should be reimplemented in all the subclasses of + Channel. + """ + raise NotImplementedError + From df9fd2c2d6055d0255970358018aaafc7b806960 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 21 Apr 2015 13:58:48 +0200 Subject: [PATCH 417/665] New channel: static error rate --- src/sage/coding/channel_constructions.py | 166 +++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 766391a3a3e..ede9b4eb1ad 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -263,3 +263,169 @@ def transmit_unsafe(self, message): """ raise NotImplementedError + + + + + + + + + +class ChannelStaticErrorRate(AbstractChannel): + r""" + Constructs a channel which adds a static number of errors to each message + it transmits. The input space and the output space of this channel + are the same. + + INPUT: + + - ``space`` -- the space of both input and output + + - ``number_errors`` -- the number of errors added to each transmitted message + It can be either an integer of a tuple. If a tuple is passed as + argument, the number of errors will be a random integer between the + two bounds of the tuple. + + EXAMPLES: + + We construct a ChannelStaticErrorRate which adds 2 errors + to any transmitted message:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan + Static error rate channel creating 2 error(s) + + We can also pass a tuple for the number of errors:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err = (1, 10) + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan + Static error rate channel creating between 1 and 10 errors + """ + + def __init__(self, space, number_errors): + r""" + TESTS: + + If the number of errors exceeds the dimension of the input space, + it will return an error:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err = 42 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + Traceback (most recent call last): + ... + ValueError: There might be more errors than the dimension of the input space + """ + super(ChannelStaticErrorRate, self).__init__(space, space) + no_err = number_errors if not hasattr(number_errors, "__iter__") else number_errors[1] + if no_err > space.dimension(): + raise ValueError("There might be more errors than the dimension of the input space") + self._number_errors = number_errors + + def __repr__(self): + r""" + Returns a string representation of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err = 42 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan + Static error rate channel creating 42 error(s) + """ + if not hasattr(self.number_errors(), "__iter__"): + return "Static error rate channel creating %s error(s)"\ + % self.number_errors() + else: + no_err = self.number_errors() + return "Static error rate channel creating between %s and %s errors"\ + % (no_err[0], no_err[1]) + + def _latex_(self): + r""" + Returns a latex representation of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err = 42 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan._latex_() + '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' + """ + if not hasattr(self.number_errors(), "__iter__"): + return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ + % self.number_errors() + else: + no_err = self.number_errors() + return "\\textnormal{Static error rate channel, creating between %s and %s errors}"\ + % (no_err[0], no_err[1]) + + def __eq__(self, other): + r""" + Checks if ``self`` is equal to ``other``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err = 42 + sage: Chan1 = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan2 = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan1 == Chan2 + True + """ + return isinstance(other, ChannelStaticErrorRate)\ + and self.input_space() == other.input_space()\ + and self.number_errors() == other.number_errors() + + def transmit_unsafe(self, message): + r""" + Returns ``message`` with as many errors as ``self._number_errors`` in it. + If ``self._number_errors`` was passed as a tuple for the number of errors, it will + pick a random integer between the bounds of the tuple and use it as the number of errors. + This method does not check if ``message`` belongs to the input space of``self``. + + INPUT: + + - ``message`` -- a vector + + OUTPUT: + + - a vector of the output space + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: msg = F((4, 8, 15, 16, 23, 42)) + sage: Chan.transmit_unsafe(msg) # random + (4, 14, 15, 16, 17, 42) + """ + number_errors = _tuple_to_integer(self.number_errors()) + V = self.input_space() + n = V.dimension() + error_vector = _random_error_vector(n, V.base_ring(),\ + _random_error_position(n, number_errors)) + return message + error_vector + + def number_errors(self): + r""" + Returns the number of errors created by ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 3 + sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan.number_errors() + 3 + """ + return self._number_errors + From 4da3b35b4127a7f6dbf6d09b4b6c55a383f5a35f Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 21 Apr 2015 14:06:42 +0200 Subject: [PATCH 418/665] Changed naming conventions and added new channel: ErrorErasure --- src/sage/coding/channel_constructions.py | 262 +++++++++++++++++++++-- 1 file changed, 243 insertions(+), 19 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index ede9b4eb1ad..dc05385327f 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -8,9 +8,9 @@ This file contains the following elements: - *AbstractChannel*, the abstract class for Channels - - *ChannelStaticErrorRate*, which creates a specific number of errors in each + - *StaticErrorRateChannel*, which creates a specific number of errors in each transmitted message - - *ChannelErrorErasure*, which creates a specific number of errors and a + - *ErrorErasureChannel*, which creates a specific number of errors and a specific number of erasures in each transmitted message """ @@ -201,7 +201,7 @@ def transmit(self, message): sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) sage: Chan.transmit(msg) # random (4, 14, 15, 16, 17, 42) @@ -210,7 +210,7 @@ def transmit(self, message): sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = (4, 8, 15, 16, 23, 42) sage: Chan.transmit(msg) Traceback (most recent call last): @@ -230,7 +230,7 @@ def input_space(self): sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan.input_space() Vector space of dimension 6 over Finite Field of size 59 @@ -245,7 +245,7 @@ def output_space(self): sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan.output_space() Vector space of dimension 6 over Finite Field of size 59 """ @@ -272,7 +272,7 @@ def transmit_unsafe(self, message): -class ChannelStaticErrorRate(AbstractChannel): +class StaticErrorRateChannel(AbstractChannel): r""" Constructs a channel which adds a static number of errors to each message it transmits. The input space and the output space of this channel @@ -289,12 +289,12 @@ class ChannelStaticErrorRate(AbstractChannel): EXAMPLES: - We construct a ChannelStaticErrorRate which adds 2 errors + We construct a StaticErrorRateChannel which adds 2 errors to any transmitted message:: sage: F = VectorSpace(GF(59), 40) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan Static error rate channel creating 2 error(s) @@ -302,7 +302,7 @@ class ChannelStaticErrorRate(AbstractChannel): sage: F = VectorSpace(GF(59), 40) sage: n_err = (1, 10) - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan Static error rate channel creating between 1 and 10 errors """ @@ -316,12 +316,12 @@ def __init__(self, space, number_errors): sage: F = VectorSpace(GF(59), 40) sage: n_err = 42 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) Traceback (most recent call last): ... ValueError: There might be more errors than the dimension of the input space """ - super(ChannelStaticErrorRate, self).__init__(space, space) + super(StaticErrorRateChannel, self).__init__(space, space) no_err = number_errors if not hasattr(number_errors, "__iter__") else number_errors[1] if no_err > space.dimension(): raise ValueError("There might be more errors than the dimension of the input space") @@ -335,7 +335,7 @@ def __repr__(self): sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan Static error rate channel creating 42 error(s) """ @@ -355,7 +355,7 @@ def _latex_(self): sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan._latex_() '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' """ @@ -375,12 +375,12 @@ def __eq__(self, other): sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 - sage: Chan1 = channels.ChannelStaticErrorRate(F, n_err) - sage: Chan2 = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan1 = channels.StaticErrorRateChannel(F, n_err) + sage: Chan2 = channels.StaticErrorRateChannel(F, n_err) sage: Chan1 == Chan2 True """ - return isinstance(other, ChannelStaticErrorRate)\ + return isinstance(other, StaticErrorRateChannel)\ and self.input_space() == other.input_space()\ and self.number_errors() == other.number_errors() @@ -403,7 +403,7 @@ def transmit_unsafe(self, message): sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) sage: Chan.transmit_unsafe(msg) # random (4, 14, 15, 16, 17, 42) @@ -423,9 +423,233 @@ def number_errors(self): sage: F = VectorSpace(GF(59), 6) sage: n_err = 3 - sage: Chan = channels.ChannelStaticErrorRate(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan.number_errors() 3 """ return self._number_errors + + + + + + + + + +class ErrorErasureChannel(AbstractChannel): + r""" + Constructs a channel which adds errors to any message it transmits. It also erases several positions + in the transmitted message. The output space of this channel is a cartesian product + between its input space and a VectorSpace of the same dimension over GF(2) + + INPUT: + + - ``space`` -- the input and output space + + - ``number_errors`` -- the number of errors created in each transmitted + message. It can be either an integer of a tuple. If an tuple is passed as + an argument, the number of errors will be a random integer between the + two bounds of this tuple. + + - ``number_erasures`` -- the number of erasures created in each transmitted + message. It can be either an integer of a tuple. If an tuple is passed as an + argument, the number of erasures will be a random integer between the + two bounds of this tuple. + + EXAMPLES: + + We construct a ErrorErasureChannel which adds 2 errors + and 2 erasures to any transmitted message:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err, n_era = 2, 2 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan + Error-and-erasure channel creating 2 error(s) and 2 erasure(s) + + We can also pass the number of errors and erasures as a couple of integers:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err, n_era = (1, 10), (1, 10) + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan + Error-and-erasure channel creating between 1 and 10 errors and between 1 and 10 erasures + """ + + def __init__(self, space, number_errors, number_erasures): + r""" + + + TESTS: + + If the sum of number of errors and number of erasures + exceeds (or may exceed, in the case of tuples) the dimension of the input space, + it will return an error:: + + sage: F = VectorSpace(GF(59), 40) + sage: n_err, n_era = 21, 21 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + Traceback (most recent call last): + ... + ValueError: The total number of errors and erasures can exceed the dimension of the input space + """ + output_space = CartesianProduct(space, VectorSpace(GF(2), space.dimension())) + super(ErrorErasureChannel, self).__init__(space, output_space) + no_err = number_errors if not hasattr(number_errors, "__iter__")\ + else number_errors[1] + no_era = number_erasures if not hasattr(number_erasures, "__iter__")\ + else number_erasures[1] + if no_err + no_era > space.dimension(): + raise ValueError("The total number of errors and erasures can exceed the dimension of the input space") + self._number_errors = number_errors + self._number_erasures = number_erasures + + def __repr__(self): + r""" + Returns a string representation of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err, n_era = 21, 21 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan + Error-and-erasure channel creating 21 error(s) and 21 erasure(s) + """ + if not hasattr(self.number_errors(), "__iter__"): + return "Error-and-erasure channel creating %s error(s) and %s erasure(s)"\ + %(self.number_errors(), self.number_erasures()) + else: + no_err = self.number_errors() + no_era = self.number_erasures() + return "Error-and-erasure channel creating between %s and %s errors and between %s and %s erasures"\ + % (no_err[0], no_err[1], no_era[0], no_era[1]) + + def _latex_(self): + r""" + Returns a latex representation of ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err, n_era = 21, 21 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: latex(Chan) + \textnormal{Error-and-erasure channel creating 21 error(s) and 21 erasure(s)} + """ + if not hasattr(self.number_errors(), "__iter__"): + return "\\textnormal{Error-and-erasure channel creating %s error(s) and %s erasure(s)}"\ + %(self.number_errors(), self.number_erasures()) + else: + no_err = self.number_errors() + no_era = self.number_erasures() + return "\\textnormal{Error-and-erasure channel creating between %s and %s errors and between %s and %s erasures}"\ + % (no_err[0], no_err[1], no_era[0], no_era[1]) + + def __eq__(self, other): + r""" + Checks if ``self`` is equal to ``other``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 50) + sage: n_err = 17 + sage: n_era = 7 + sage: Chan1 = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan2 = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan1 == Chan2 + True + """ + return isinstance(other, ErrorErasureChannel)\ + and self.input_space() == other.input_space()\ + and self.number_errors() == other.number_errors()\ + and self.number_erasures() == other.number_erasures() + + def transmit_unsafe(self, message): + r""" + Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures + as ``self._number_erasures`` in it. + If ``self._number_errors`` was passed as an tuple for the number of errors, it will + pick a random integer between the bounds of the tuple and use it as the number of errors. + The same method applies with ``self._number_erasures``. + + All erased positions are set to 0 in the transmitted message. + It is guaranteed that the erasures and the errors will never overlap: + the received message will always contains exactly as many errors and erasures + as expected. + + This method does not check if ``message`` belongs to the input space of``self``. + + INPUT: + + - ``message`` -- a vector + + OUTPUT: + + - a couple of vectors, namely: + + - the transmitted message, which is ``message`` with erroneous and erased positions + - the erasure vector, which contains ``1`` at the erased positions of the transmitted message + , 0 elsewhere. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 11) + sage: n_err, n_era = 2, 2 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3)) + sage: Chan.transmit_unsafe(msg) # random + ((0, 14, 15, 0, 26, 53, 45, 9, 7, 14, 3), (1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) + """ + number_errors = _tuple_to_integer(self.number_errors()) + number_erasures = _tuple_to_integer(self.number_erasures()) + V = self.input_space() + n = V.dimension() + + erroneous_positions = _random_error_position(n,\ + number_errors + number_erasures) + error_split = _random_error_position(number_errors + number_erasures,\ + number_errors) + error_positions = [ erroneous_positions[i] for i in\ + range(number_errors + number_erasures) if i in error_split ] + erasure_positions = [ erroneous_positions[i] for i in\ + range(number_errors + number_erasures) if i not in error_split] + + error_vector = _random_error_vector(n, V.base_ring(), error_positions) + erasure_vector = _random_error_vector(n , GF(2), erasure_positions) + + message = message + error_vector + + for i in erasure_positions: + message[i] = 0 + return message, erasure_vector + + def number_errors(self): + r""" + Returns the number of errors created by ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err, n_era = 3, 0 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan.number_errors() + 3 + """ + return self._number_errors + + def number_erasures(self): + r""" + Returns the number of erasures created by ``self``. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err, n_era = 0, 3 + sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan.number_erasures() + 3 + """ + return self._number_erasures From 62a2447c45d3d2878f2da037ea4721464bef2ea4 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Tue, 21 Apr 2015 14:10:19 +0200 Subject: [PATCH 419/665] Channels are now part of the reference manual for coding. Added imports. --- src/doc/en/reference/coding/index.rst | 2 ++ src/sage/coding/all.py | 4 ++++ src/sage/coding/channel_constructions.py | 4 ++-- src/sage/coding/channels_catalog.py | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/sage/coding/channels_catalog.py diff --git a/src/doc/en/reference/coding/index.rst b/src/doc/en/reference/coding/index.rst index 293158d8682..004458eba3f 100644 --- a/src/doc/en/reference/coding/index.rst +++ b/src/doc/en/reference/coding/index.rst @@ -6,6 +6,8 @@ Coding Theory .. toctree:: :maxdepth: 1 + sage/coding/channels_catalog + sage/coding/channel_constructions sage/coding/codes_catalog sage/coding/linear_code sage/coding/code_constructions diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 7512aac7a6d..9627cd1c796 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -74,3 +74,7 @@ ["Krawtchouk", "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space"]) lazy_import('sage.coding', 'codes_catalog', 'codes') +lazy_import('sage.coding', 'channels_catalog', 'channels') + +import sage.coding.channel_constructions + diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index dc05385327f..47de2668f41 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -126,10 +126,10 @@ class AbstractChannel(object): r""" Abstract top-class for Channel objects. - All channel objects must heritate from this class. To implement a channel subclass, one should + All channel objects must inherit from this class. To implement a channel subclass, one should do the following: - - heritate from this class, + - inherit from this class, - call the super constructor, diff --git a/src/sage/coding/channels_catalog.py b/src/sage/coding/channels_catalog.py new file mode 100644 index 00000000000..625826d4bd7 --- /dev/null +++ b/src/sage/coding/channels_catalog.py @@ -0,0 +1,17 @@ +r""" +Index of Channels + +The ``channels`` object may be used to access the codes that Sage can build. + +- :func:`channel_constructions.ErrorErasureChannel ` +- :func:`channel_constructions.StaticErrorRateChannel ` + +.. NOTE:: + + To import these names into the global namespace, use: + + sage: from sage.coding.channels_catalog import * + +""" + +from channel_constructions import (ErrorErasureChannel, StaticErrorRateChannel) From abcb076cf7ae487d9a34b690b415df40886fd93f Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 21 Apr 2015 15:34:11 +0200 Subject: [PATCH 420/665] 16659: renaming thanks to Franco's remarks, refactoring lifing_idempotent, documentation --- .../finite_dimensional_algebras_with_basis.py | 166 +++++++++++------- src/sage/categories/semisimple_algebras.py | 49 ++++-- 2 files changed, 141 insertions(+), 74 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 08829d12b84..fdd41b80306 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -12,7 +12,7 @@ #****************************************************************************** import operator -from sage.misc.cachefunc import cached_method, cached_function +from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.algebras import Algebras from sage.categories.associative_algebras import AssociativeAlgebras @@ -434,9 +434,10 @@ def principal_ideal(self, a, side='left'): return self.submodule([(a * b if side=='right' else b * a) for b in self.basis()]) - def central_orthogonal_idempotents(self): + @cached_method + def orthogonal_idempotents_central_mod_rad(self): r""" - Return a maximal family of central orthogonal idempotents of + Return a maximal family of primitive orthogonal idempotents of ``self``. INPUT: @@ -450,12 +451,29 @@ def central_orthogonal_idempotents(self): ALGORITHM: - Let '\overline{e}' be a central orthogonal idempotent of the - semisimple quotient `\overline{A}` of a finite dimensional algebra - `A`. Let `e \in A` such that the projection of `e` in - `\overline{A}` is `\overline{e}`. We iterate the formula - `1 - (1 - e^2)^2` until having an idempotent. See [CR62] for - correctness and termination proofs. + The primitive orthogonal idempotents of `A` are obtained by lifting + the central orthogonal idempotents of the semisimple quotient + `\overline{A}`. + + Let `\pi` be the projection `A \rightarrow \overline{A}`. + + Fact: for `\overline{e}` a central orthogonal idempotent of + `\overline{A}`, we construct `e \in A` idempotent such that `\pi(e) + = \overline{e}`. Namely, we find an element of `A` for which the + projection on `\overline{A}` is `\overline(e)` via the method + :meth:`lift`, and then iterate the formula `1 - (1 - e^2)^2` until + having an idempotent. + + Let `(\overline{e_i})` be a set of central orthogonal idempotents + of the semisimple quotient of `A` and `(e_i)` their lift in `A`. + We recursively construct orthogonal idempotents of `A`: if + `(f_i)_{i < n}` is a set of already constructed orthogonal + idempotent, then we can construct `f_n` by lifting the element + `(1 - \sum_{i < n} f_i) e_n (1 - \sum_{i < n} f_i)`. + + See [CR62] for correctness and termination + proofs. + EXAMPLES:: @@ -464,7 +482,7 @@ def central_orthogonal_idempotents(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.central_orthogonal_idempotents() + sage: A.orthogonal_idempotents_central_mod_rad() [y, x] :: @@ -473,16 +491,22 @@ def central_orthogonal_idempotents(self): An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) - sage: orth = A.central_orthogonal_idempotents(); orth + sage: orth = A.orthogonal_idempotents_central_mod_rad(); orth [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], -1/2*B[3] + 1/2*B[9], B[0], - -B[0] + 1/2*B[4] + 1/2*B[8], + 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] + sage: all(e*e == e for e in orth) + True + sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) + True + + We construct the minimal orthogonal idempotents of the `0`-Hecke monoid algebra:: @@ -494,7 +518,7 @@ def central_orthogonal_idempotents(self): sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()); M A submonoid of (Maps from W to itself) with 3 generators sage: A = M.algebra(QQ) - sage: orth = A.central_orthogonal_idempotents() + sage: orth = A.orthogonal_idempotents_central_mod_rad() sage: all(e*e == e for e in orth) True sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) @@ -505,25 +529,21 @@ def central_orthogonal_idempotents(self): We test that the above idempotents are central orthogonal idempotents:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: E = A.central_orthogonal_idempotents() + sage: E = A.orthogonal_idempotents_central_mod_rad() sage: all(e.is_idempotent() for e in E) True sage: all(e * f == 0 for e in E for f in E if e != f) True - sage: all(e * b == b * e for b in A.basis() for e in E) - True :: sage: Z12 = Monoids().Finite().example() sage: A = Z12.algebra(QQ) - sage: E = A.central_orthogonal_idempotents() + sage: E = A.orthogonal_idempotents_central_mod_rad() sage: all(e.is_idempotent() for e in E) True sage: all(e * f == 0 for e in E for f in E if e != f) True - sage: all(e * b == b * e for b in A.basis() for e in E) - True :: @@ -533,13 +553,11 @@ def central_orthogonal_idempotents(self): sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()) sage: A = M.algebra(QQ) - sage: E = A.central_orthogonal_idempotents() + sage: E = A.orthogonal_idempotents_central_mod_rad() sage: all(e.is_idempotent() for e in E) True sage: all(e * f == 0 for e in E for f in E if e != f) True - sage: all(e * b == b * e for b in A.basis() for e in E) - True REFERENCES: @@ -548,28 +566,57 @@ def central_orthogonal_idempotents(self): algebras." Pure and Applied Mathematics, Vol. XI Interscience Publishers, a division of John Wiley & Sons, New York-London 1962 - pp 545--546 + pp 545--547 TODO: More documentation, explanation algorithm """ - def lift(idemp, one): - idempOld = None - while idemp != idempOld: - tmp = idemp - idemp = (one - (one - idemp**2)**2) - idempOld = tmp - return idemp Aquo = self.semisimple_quotient() one = self.one() - orths = [lift(x.lift(), one) for x in Aquo.central_orthogonal_idempotents()] # Construction of the orthogonal idempotents idems = [] f = 0 - for g in orths: - idems.append(lift((one - f) * g * (one - f), one)) + for g in Aquo.central_orthogonal_idempotents(): + idems.append(self.lifting_idempotent((one - f) * g.lift() * (one - f))) f = f + idems[-1] return idems + def lifting_idempotent(self, x): + r""" + Return an idempotent of self with same image as `x` in the + semisimple quotient. If `x` is an element of the semisimple + quotient, return an idempotent of `A` with image `x`. + + INPUT: + + - `x` -- an element of an algebra `A` + + OUTPUT: + + - an idempotent of `A` with image + 1. `\pi(x)` if `x \in A` + 2. `x` if `x` is the semisimple quotient of `A` + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: S = A.semisimple_quotient() + sage: A.lifting_idempotent(S.basis()['x']) + x + sage: A.lifting_idempotent(A.basis()['y']) + y + """ + if not self.is_parent_of(x): + x = x.lift() + p = self.semisimple_quotient().retract(x) + assert (p*p == p) + xOld = None + one = self.one() + while x != xOld: + tmp = x + x = (one - (one - x**2)**2) + xOld = tmp + return x + @cached_method def cartan_invariants_matrix(self, side='left'): r""" @@ -624,10 +671,10 @@ def cartan_invariants_matrix(self, side='left'): dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in orth_quo] # Orthogonal idempotents - orth = self.central_orthogonal_idempotents() + orth = self.orthogonal_idempotents_central_mod_rad() return Matrix(self.base_ring(), len(orth), - lambda i,j: self.pierce_decomposition_component(orth[i], + lambda i,j: self.peirce_summand(orth[i], orth[j]).dimension()/(dimSimples[i]*dimSimples[j])) def projective_indecomposables(self, side='left'): @@ -639,8 +686,8 @@ def projective_indecomposables(self, side='left'): sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: projs = A.projective_indecomposables(); projs - [Free module generated by {0} over Rational Field, - Free module generated by {0, 1, 2} over Rational Field] + [Free module generated by {0, 1, 2} over Rational Field, + Free module generated by {0} over Rational Field] We check that the sum of the dimensions of the indecomposable projective module is the dimension of ``self``: @@ -649,37 +696,42 @@ def projective_indecomposables(self, side='left'): True """ - return [self.principal_ideal(e, side) for e in self.central_orthogonal_idempotents()] + return [self.principal_ideal(e, side) for e in + self.orthogonal_idempotents_central_mod_rad()] - def pierce_decomposition_component(self, ei, ej): + @cached_method + def peirce_summand(self, ei, ej): r""" - Return the Pierce decomposition component of ``self``. + Return the Peirce decomposition summand `e_i A e_j` as a + subspace of the algebra. INPUT: - ``self`` -- an algebra `A` - - `e_i` -- an idempotent of ``self`` - - `e_j` -- an idempotent of ``self`` + - `e_i` -- an idempotent of `A` + - `e_j` -- an idempotent of `A` OUTPUT: - - `e_i A e_j` as a subspace of ``self`` + - `e_i A e_j` as a subspace of `A` + + .. SEEALSO:: + :meth:`peirce_decomposition` EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: idemp = A.central_orthogonal_idempotents() - sage: A.pierce_decomposition_component(idemp[1], idemp[0]) + sage: idemp = A.orthogonal_idempotents_central_mod_rad() + sage: A.peirce_summand(idemp[1], idemp[0]) Free module generated by {0, 1} over Rational Field - sage: A.pierce_decomposition_component(idemp[0], idemp[1]) + sage: A.peirce_summand(idemp[0], idemp[1]) Free module generated by {} over Rational Field - - We recover the unique 2 dimensional representations of S4:: + We recover the unique 2 dimensional representation of S4:: sage: A4 = SymmetricGroup(4).algebra(QQ) sage: e = A4.central_orthogonal_idempotents()[2] - sage: A4.pierce_decomposition_component(e, e) + sage: A4.peirce_summand(e, e) Free module generated by {0, 1, 2, 3} over Rational Field """ B = self.basis() @@ -689,13 +741,10 @@ def pierce_decomposition_component(self, ei, ej): return self.submodule([self.from_vector(v) for v in ideal.basis()], already_echelonized=True) - def pierce_decomposition(self): - r""" - Return the Pierce decomposition of ``self``. - Let `A` be a finite dimensional algebra. - The Pierce decomposition of `A` is the - decomposition of `A` into the subspaces + def peirce_decomposition(self): + r""" + Return the Peirce decomposition of ``self``. TODO: polish this @@ -708,7 +757,7 @@ def pierce_decomposition(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.pierce_decomposition() + sage: A.peirce_decomposition() [Free module generated by {0} over Rational Field, Free module generated by {} over Rational Field, Free module generated by {0, 1} over Rational Field, Free module generated by {0} over @@ -717,9 +766,8 @@ def pierce_decomposition(self): """ import itertools decomp = [] - for (ei, ej) in itertools.product(self.central_orthogonal_idempotents(), - repeat=2): - decomp.append(self.pierce_decomposition_component(ei, ej)) + for (ei, ej) in itertools.product(self.orthogonal_idempotents_central_mod_rad(), repeat=2): + decomp.append(self.peirce_summand(ei, ej)) return decomp diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index c9765127415..65c676ecb9a 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -116,29 +116,44 @@ class ParentMethods: @cached_method def central_orthogonal_idempotents(self): r""" - Return a maximal list of orthogonal idempotents of + Return a maximal list of central orthogonal idempotents of ``self``. + Central orthogonal idempotents of an algebra `A` are + idempotents `(e_1, \dots, e_n)` such that `e_i e_j = 0` if + `i \neq j`. Moreover, all `e_i` commute with all elements + of `A` (central). + INPUT: - - ``self`` -- semisimple algebra + - ``self`` -- a semisimple algebra + + OUTPUT: + + - a complete list of central orthogonal idempotents. EXAMPLES:: + sage: import itertools sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: A3.central_orthogonal_idempotents() + sage: orths = A3.central_orthogonal_idempotents(); orths [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), 1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] - + sage: all(e*e == e for e in orths) + True + sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orths, orths) if e != f) + True + sage: all(e*a == a*e for e in orths for a in A3.basis()) + True :: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing - the arrows a:x->y and b:x->y) over Rational Field + the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() sage: Aquo.central_orthogonal_idempotents() [B['y'], B['x']] @@ -146,6 +161,7 @@ def central_orthogonal_idempotents(self): return [x.lift() for x in self.center().central_orthogonal_idempotents()] + class Commutative(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -153,21 +169,24 @@ class ParentMethods: @cached_method def _orthogonal_decomposition(self, generators=None): r""" - Return a list of orthogonal idempotents of a semisimple - commutative finite dimensional algebra ``self``. + Return a list of orthogonal quasi-idempotents of a + semisimple commutative finite dimensional algebra + ``self``. INPUT: - ``self`` a finite dimensional semisimple commutative - algebra. + algebra - ``generators`` a list of generators of ``self``. By - default it will be the basis of ``self``. + default it will be the basis of ``self`` OUTPUT: - list of elements of ``self`` each generating a one dimensional simple submodule of ``self`` in direct - sum with the others. The list is maximal. + sum with the others. The list is maximal in the sens + that no quasi-idempotent `e` can be decomposed as a + sum `e = e_1 + e_2` of quasi-idempotents elements. ALGORITHM: @@ -254,10 +273,10 @@ def central_orthogonal_idempotents(self): EXAMPLES:: + sage: import itertools sage: A5 = SymmetricGroup(5).algebra(QQ) sage: Z5 = A5.center() - sage: orth = Z5.central_orthogonal_idempotents() - sage: orth + sage: orths = Z5.central_orthogonal_idempotents(); orths [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + 1/120*B[5] + 1/120*B[6], 1/120*B[0] - 1/120*B[1] + @@ -268,9 +287,9 @@ def central_orthogonal_idempotents(self): 1/24*B[5], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] - sage: orth[2] * orth[4] - 0 - sage: orth[1] ** 2 == orth[1] + sage: all(e*e == e for e in orths) + True + sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orths, orths) if e != f) True """ return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for From 6f3308a8ce70a2141ab76395b1026afd42292d91 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 21 Apr 2015 16:08:54 +0200 Subject: [PATCH 421/665] 16659: typo doc --- .../finite_dimensional_algebras_with_basis.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fdd41b80306..ffbb3e2ea49 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -437,8 +437,9 @@ def principal_ideal(self, a, side='left'): @cached_method def orthogonal_idempotents_central_mod_rad(self): r""" - Return a maximal family of primitive orthogonal idempotents of - ``self``. + Return a maximal family of orthogonal idempotents of + ``self`` obtained by lifting the central orthogonal idempotents of + the semisimple quotient. INPUT: @@ -446,13 +447,12 @@ def orthogonal_idempotents_central_mod_rad(self): OUTPUT: - - a list of a complete set of orthogonal idempotents of the - algebra. + - a list of orthogonal idempotents of the algebra. ALGORITHM: - The primitive orthogonal idempotents of `A` are obtained by lifting - the central orthogonal idempotents of the semisimple quotient + The orthogonal idempotents of `A` are obtained by lifting the + central orthogonal idempotents of the semisimple quotient `\overline{A}`. Let `\pi` be the projection `A \rightarrow \overline{A}`. @@ -526,7 +526,7 @@ def orthogonal_idempotents_central_mod_rad(self): TESTS: - We test that the above idempotents are central orthogonal idempotents:: + We test that the above idempotents are orthogonal idempotents:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: E = A.orthogonal_idempotents_central_mod_rad() From 9b1e0985e09c7181860d43f41f394cc23103ce1c Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 21 Apr 2015 10:10:26 -0400 Subject: [PATCH 422/665] Updated Sage version to 6.7.beta2 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 2 +- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 87e71af1294..c76ad65caad 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.7.beta1, released 2015-04-15 +Sage version 6.7.beta2, released 2015-04-21 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 63b519e8ce1..324c8f4955b 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=ca70b58ba6c8bd0bbcab9ed5408f9f43dde8fffa -md5=02a841e6f9e8915d674ac2180447562b -cksum=923598272 +sha1=cfa4d6a576b31399a5a7c95e5ca7eaafd7bc79fd +md5=6f1978763cfa1d7534a2bf64be00d390 +cksum=1608967615 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 84df3526d80..d22307c427b 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -87 +88 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index daa5404a1da..0e51a90491a 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.7.beta1, Release Date: 2015-04-15 │ +│ SageMath Version 6.7.beta2, Release Date: 2015-04-21 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 3b94f8e2f7c..34bdaebad59 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='6.7.beta1' -SAGE_RELEASE_DATE='2015-04-15' +SAGE_VERSION='6.7.beta2' +SAGE_RELEASE_DATE='2015-04-21' diff --git a/src/sage/version.py b/src/sage/version.py index 761d290d7f9..cf52bc2b13a 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '6.7.beta1' -date = '2015-04-15' +version = '6.7.beta2' +date = '2015-04-21' From 5155b323c7407569430e42998098c8727fc66d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 21 Apr 2015 16:29:23 +0200 Subject: [PATCH 423/665] 16659: removed Algebras.Subobjects.ElementMethods._mul_ which duplicates Semigroups.Subquotients.ParentMethods.product + doc updates --- src/sage/categories/algebras.py | 26 ------------------- .../finite_dimensional_algebras_with_basis.py | 8 +++--- src/sage/categories/magmas.py | 9 +++++++ 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 32c7783e1df..5e81cee137a 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -242,29 +242,3 @@ def extra_super_categories(self): """ from sage.categories.coalgebras import Coalgebras return [Coalgebras(self.base_category().base_ring())] - - - class Subobjects(SubobjectsCategory): - - class ElementMethods: - - def _mul_(self, right): - r""" - Product of two elements. - - INPUT: - - - ``self``, ``right`` -- two elements - - If `B` is a `SubModuleWithBasis` of `A`, then the - multiplication law of `B` is inherited from `A`. - - EXAMPLES:: - - sage: Z = SymmetricGroup(5).algebra(QQ).center() - sage: B = Z.basis() - sage: B[3] * B[2] - 4*B[2] + 6*B[3] + 5*B[6] - """ - p = self.parent() - return p.retract(self.lift() * right.lift()) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fdd41b80306..10108b666e2 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -391,13 +391,13 @@ def center(self): def principal_ideal(self, a, side='left'): r""" - Construct the ``side`` module generated by ``a``. + Construct the ``side`` principal ideal generated by ``a``. EXAMPLES: - In order to highlight the difference between left and right - principal ideals, our first example deals with a non commutative - algebra:: + In order to highlight the difference between left and + right principal ideals, our first example deals with a non + commutative algebra:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 5794fa2754f..ea471ae34b5 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -1044,8 +1044,17 @@ def product(self, x, y): EXAMPLES:: sage: S = Semigroups().Subquotients().example() + sage: S + An example of a (sub)quotient semigroup: a quotient of the left zero semigroup sage: S.product(S(19), S(3)) 19 + + Here is a more elaborate example involving a sub algebra:: + + sage: Z = SymmetricGroup(5).algebra(QQ).center() + sage: B = Z.basis() + sage: B[3] * B[2] + 4*B[2] + 6*B[3] + 5*B[6] """ assert(x in self) assert(y in self) From 4d72964f090830c6fa01e98588395136506f9eed Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 21 Apr 2015 18:18:01 +0200 Subject: [PATCH 424/665] 16659: revert radical_basis, documentation --- src/doc/en/reference/categories/index.rst | 1 + .../finite_dimensional_algebras_with_basis.py | 180 ++++++++---------- 2 files changed, 80 insertions(+), 101 deletions(-) diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index a4f41af65e6..1d920a61767 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -147,6 +147,7 @@ Categories sage/categories/schemes sage/categories/semigroups sage/categories/semirings + sage/categories/semisimple_algebras sage/categories/sets_cat sage/categories/sets_with_grading sage/categories/sets_with_partial_maps diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index ffbb3e2ea49..5caf4b3672c 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -1,6 +1,16 @@ # -*- coding: utf-8 -*- r""" Finite dimensional algebras with basis + + +REFERENCES: + +.. [CR62] Curtis, Charles W.; Reiner, Irving + "Representation theory of finite groups and associative + algebras." + Pure and Applied Mathematics, Vol. XI Interscience Publishers, a + division of John Wiley & Sons, New York-London 1962 + pp 545--547 """ #***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) @@ -155,25 +165,19 @@ def radical_basis(self): from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + product_on_basis = self.product_on_basis + if p == 0: - index_set = list(self.basis().keys()) - - cached_products = {} - for y in index_set: - for i in index_set: - cached_products[y, i] = self.product_on_basis(y, i) - - mat = [] - for y in index_set: - row = [] - for x in index_set: - row.append( F.sum(cached_products[x, j][i] * - cached_products[y, i][j] - for i in index_set - for j in index_set) ) - mat.append(row) - mat = matrix(self.base_ring(), mat) + keys = list(self.basis().keys()) + cache = [{(i,j): c + for i in keys + for j,c in product_on_basis(y,i)} + for y in keys] + mat = [ [ sum(x.get((j, i), 0) * c for (i,j),c in y.items()) + for x in cache] + for y in cache] + mat = matrix(self.base_ring(), mat) rad_basis = mat.kernel().basis() else: @@ -437,9 +441,8 @@ def principal_ideal(self, a, side='left'): @cached_method def orthogonal_idempotents_central_mod_rad(self): r""" - Return a maximal family of orthogonal idempotents of - ``self`` obtained by lifting the central orthogonal idempotents of - the semisimple quotient. + Return a family of orthogonal idempotents of ``self`` that project + on the central orthogonal idempotents of the semisimple quotient. INPUT: @@ -447,7 +450,8 @@ def orthogonal_idempotents_central_mod_rad(self): OUTPUT: - - a list of orthogonal idempotents of the algebra. + - a list of orthogonal idempotents obtained by lifting the central + orthogonal idempotents of the semisimple quotient. ALGORITHM: @@ -455,24 +459,14 @@ def orthogonal_idempotents_central_mod_rad(self): central orthogonal idempotents of the semisimple quotient `\overline{A}`. - Let `\pi` be the projection `A \rightarrow \overline{A}`. - - Fact: for `\overline{e}` a central orthogonal idempotent of - `\overline{A}`, we construct `e \in A` idempotent such that `\pi(e) - = \overline{e}`. Namely, we find an element of `A` for which the - projection on `\overline{A}` is `\overline(e)` via the method - :meth:`lift`, and then iterate the formula `1 - (1 - e^2)^2` until - having an idempotent. - Let `(\overline{e_i})` be a set of central orthogonal idempotents of the semisimple quotient of `A` and `(e_i)` their lift in `A`. We recursively construct orthogonal idempotents of `A`: if `(f_i)_{i < n}` is a set of already constructed orthogonal - idempotent, then we can construct `f_n` by lifting the element + idempotent, we then construct `f_n` by lifting the element `(1 - \sum_{i < n} f_i) e_n (1 - \sum_{i < n} f_i)`. - See [CR62] for correctness and termination - proofs. + See [CR62] for correctness and termination proofs. EXAMPLES:: @@ -488,8 +482,7 @@ def orthogonal_idempotents_central_mod_rad(self): :: sage: Z12 = Monoids().Finite().example(); Z12 - An example of a finite multiplicative monoid: the integers - modulo 12 + An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) sage: orth = A.orthogonal_idempotents_central_mod_rad(); orth [-1/2*B[8] + 1/2*B[4], @@ -506,8 +499,6 @@ def orthogonal_idempotents_central_mod_rad(self): sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) True - - We construct the minimal orthogonal idempotents of the `0`-Hecke monoid algebra:: @@ -523,52 +514,6 @@ def orthogonal_idempotents_central_mod_rad(self): True sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) True - - TESTS: - - We test that the above idempotents are orthogonal idempotents:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: E = A.orthogonal_idempotents_central_mod_rad() - sage: all(e.is_idempotent() for e in E) - True - sage: all(e * f == 0 for e in E for f in E if e != f) - True - - :: - - sage: Z12 = Monoids().Finite().example() - sage: A = Z12.algebra(QQ) - sage: E = A.orthogonal_idempotents_central_mod_rad() - sage: all(e.is_idempotent() for e in E) - True - sage: all(e * f == 0 for e in E for f in E if e != f) - True - - :: - - sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup - sage: W = WeylGroup(['A', 3]); W.rename("W") - sage: ambient_monoid = FiniteSetMaps(W, action="right") - sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()) - sage: A = M.algebra(QQ) - sage: E = A.orthogonal_idempotents_central_mod_rad() - sage: all(e.is_idempotent() for e in E) - True - sage: all(e * f == 0 for e in E for f in E if e != f) - True - - REFERENCES: - - .. [CR62] Curtis, Charles W.; Reiner, Irving - "Representation theory of finite groups and associative - algebras." - Pure and Applied Mathematics, Vol. XI Interscience Publishers, a - division of John Wiley & Sons, New York-London 1962 - pp 545--547 - - TODO: More documentation, explanation algorithm """ Aquo = self.semisimple_quotient() one = self.one() @@ -576,33 +521,48 @@ def orthogonal_idempotents_central_mod_rad(self): idems = [] f = 0 for g in Aquo.central_orthogonal_idempotents(): - idems.append(self.lifting_idempotent((one - f) * g.lift() * (one - f))) + idems.append(self.indempotent_lift((one - f) * g.lift() * (one - f))) f = f + idems[-1] return idems - def lifting_idempotent(self, x): + def indempotent_lift(self, x): r""" - Return an idempotent of self with same image as `x` in the - semisimple quotient. If `x` is an element of the semisimple - quotient, return an idempotent of `A` with image `x`. + Return an idempotent of ``self`` which projection on the semisimple + quotient is the same as `x`. + + Let `\pi` be the projection `A \rightarrow \overline{A}` on the + quotient by the radical. INPUT: - - `x` -- an element of an algebra `A` + 1. either `x` -- an idempotent of the semisimple quotient of `A` + 2. or `x` -- an element of an algebra `A` which project on an + idempotent element of the semisimple quotient of `A` OUTPUT: - - an idempotent of `A` with image - 1. `\pi(x)` if `x \in A` - 2. `x` if `x` is the semisimple quotient of `A` + 1. if `x` is in the semisimple quotient of `A`, return an idempotent + `e` such that `\pi(e) = x`. + 2. if `x` is in `A`, return the unique idempotent `e` of `A` such + that `\pi(e) = \pi(x)` and `e` is polynomial in `x`. + + ALGORITHM: + + For `\overline{e}` an idempotent of `\overline{A}`, we construct `e + \in A` idempotent such that `\pi(e) = \overline{e}`. Namely, we + find an element of `A` for which the projection on `\overline{A}` + is `\overline{e}` and then iterate the formula `1 - (1 - e^2)^2` + until having an idempotent. + + See [CR62] for correctness and termination proofs. EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: S = A.semisimple_quotient() - sage: A.lifting_idempotent(S.basis()['x']) + sage: A.indempotent_lift(S.basis()['x']) x - sage: A.lifting_idempotent(A.basis()['y']) + sage: A.indempotent_lift(A.basis()['y']) y """ if not self.is_parent_of(x): @@ -677,15 +637,32 @@ def cartan_invariants_matrix(self, side='left'): lambda i,j: self.peirce_summand(orth[i], orth[j]).dimension()/(dimSimples[i]*dimSimples[j])) - def projective_indecomposables(self, side='left'): + def projective_isotypics(self, side='left'): r""" - Return the list of indecomposable projective ``side`` - ``self``-modules. + Return the list of isotypic projective ``side`` ``self``-modules. + + Let `(e_i)` be the orthogonal idempotents lifted from the central + orthogonal idempotents of the semisimple algebra. The regular + representation `A` can be decomposed as a direct sum + `\bigoplus_i P_i` with `P_i = e_i A`. + The projective modules `P_i` are isotypic in the sense that all + their direct summands are isomoprhic. + + .. NOTE:: + + The number of summands of `P_i` is the dimension of the associated + simple module. + + OUTPUT: + + - return a list of modules `e_i A` for `(e_i)` a set of orthogonal + idempotents lifted from central orthogonal idempotents of the + semisimple quotient. EXAMPLES:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: projs = A.projective_indecomposables(); projs + sage: projs = A.projective_isotypics(side="left"); projs [Free module generated by {0, 1, 2} over Rational Field, Free module generated by {0} over Rational Field] @@ -746,13 +723,14 @@ def peirce_decomposition(self): r""" Return the Peirce decomposition of ``self``. - TODO: polish this + Let `(e_i)` be orthogonal idempotents of `A` with sum `1`, + then `A` is the direct sum of the subspaces `e_i A e_j`. OUTPUT: The list of subspaces `e_i A e_j`, where `e_i` and `e_j` run - through a complete system of primitive orthogonal idempotents of - this algebra `A`. + through the commuting orthogonal idempotents lifted from the + central orthogonal idempotents of the semisimple quotient. EXAMPLES:: From 58c17fbe84b31e534be250907717c52b8827e1d8 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 21 Apr 2015 21:46:04 +0200 Subject: [PATCH 425/665] cimport PyWeakref_GetObject() from cpython.weakref --- src/sage/structure/coerce_dict.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/coerce_dict.pyx b/src/sage/structure/coerce_dict.pyx index 49d548362f4..7fd9bdd9bdb 100644 --- a/src/sage/structure/coerce_dict.pyx +++ b/src/sage/structure/coerce_dict.pyx @@ -45,6 +45,7 @@ used with weak references on the values. from cpython.object cimport * from cpython.list cimport PyList_New from cpython.mem cimport * +from cpython.weakref cimport PyWeakref_GetObject from cpython.string cimport PyString_FromString from cpython cimport Py_XINCREF, Py_XDECREF from libc.string cimport memset @@ -63,7 +64,6 @@ cdef type fixed_ref = ref from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer cdef extern from "Python.h": - PyObject* PyWeakref_GetObject(object r) PyObject* Py_None int PyList_SetItem(object list, Py_ssize_t index, PyObject * item) except -1 From 06de5188ee34750760d480c1920afcfc1f40408d Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Tue, 21 Apr 2015 22:15:40 +0200 Subject: [PATCH 426/665] 16659: documentation and typos --- .../finite_dimensional_algebras_with_basis.py | 62 ++++++++++++------- src/sage/categories/semisimple_algebras.py | 46 +++++++------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 5caf4b3672c..9fc1e5470b0 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -468,6 +468,8 @@ def orthogonal_idempotents_central_mod_rad(self): See [CR62] for correctness and termination proofs. + .. SEEALSO:: :meth:`idempotent_lift` + EXAMPLES:: @@ -521,11 +523,11 @@ def orthogonal_idempotents_central_mod_rad(self): idems = [] f = 0 for g in Aquo.central_orthogonal_idempotents(): - idems.append(self.indempotent_lift((one - f) * g.lift() * (one - f))) + idems.append(self.idempotent_lift((one - f) * g.lift() * (one - f))) f = f + idems[-1] return idems - def indempotent_lift(self, x): + def idempotent_lift(self, x): r""" Return an idempotent of ``self`` which projection on the semisimple quotient is the same as `x`. @@ -560,15 +562,16 @@ def indempotent_lift(self, x): sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() sage: S = A.semisimple_quotient() - sage: A.indempotent_lift(S.basis()['x']) + sage: A.idempotent_lift(S.basis()['x']) x - sage: A.indempotent_lift(A.basis()['y']) + sage: A.idempotent_lift(A.basis()['y']) y """ if not self.is_parent_of(x): x = x.lift() p = self.semisimple_quotient().retract(x) - assert (p*p == p) + if p*p != p: + raise ValueError("%s does not retract to an idempotent."%p) xOld = None one = self.one() while x != xOld: @@ -578,9 +581,13 @@ def indempotent_lift(self, x): return x @cached_method - def cartan_invariants_matrix(self, side='left'): + def cartan_invariants_matrix(self): r""" - Return the Cartan invariants matrix of the algebra ``self``. + Return the Cartan invariants matrix of the algebra. + + OUTPUT: + + - The Cartan invariants matrix of the algebra. EXAMPLES:: @@ -628,7 +635,7 @@ def cartan_invariants_matrix(self, side='left'): Aquo = self.semisimple_quotient() orth_quo = Aquo.central_orthogonal_idempotents() # Dimension of simple modules - dimSimples = [sqrt(Aquo.principal_ideal(e, side).dimension()) for e in + dimSimples = [sqrt(Aquo.principal_ideal(e).dimension()) for e in orth_quo] # Orthogonal idempotents orth = self.orthogonal_idempotents_central_mod_rad() @@ -646,7 +653,7 @@ def projective_isotypics(self, side='left'): representation `A` can be decomposed as a direct sum `\bigoplus_i P_i` with `P_i = e_i A`. The projective modules `P_i` are isotypic in the sense that all - their direct summands are isomoprhic. + their direct summands are isomorphic. .. NOTE:: @@ -692,8 +699,7 @@ def peirce_summand(self, ei, ej): - `e_i A e_j` as a subspace of `A` - .. SEEALSO:: - :meth:`peirce_decomposition` + .. SEEALSO:: :meth:`peirce_decomposition` EXAMPLES:: @@ -719,18 +725,28 @@ def peirce_summand(self, ei, ej): already_echelonized=True) - def peirce_decomposition(self): + def peirce_decomposition(self, list_idempotents=None, check=True): r""" Return the Peirce decomposition of ``self``. - Let `(e_i)` be orthogonal idempotents of `A` with sum `1`, + Let `(e_i)` be a set of orthogonal idempotents of `A` with sum `1`, then `A` is the direct sum of the subspaces `e_i A e_j`. + INPUT: + + - ``list_idempotents`` -- (default: None) A list of orthogonal + idempotents of the algebra. By default, the list of orthogonal + idempotents will be lifted from the central orthogonal + idempotents of the semisimple quotient. + - ``check`` -- (default: True) If set to True ``list_idempotents`` + is checked to be orthogonal. + OUTPUT: - The list of subspaces `e_i A e_j`, where `e_i` and `e_j` run - through the commuting orthogonal idempotents lifted from the - central orthogonal idempotents of the semisimple quotient. + - The list of subspaces `e_i A e_j`, where `e_i` and `e_j` run + through ``list_idempotents``. + + .. SEEALSO:: :meth:`orthogonal_idempotents_central_mod_rad` EXAMPLES:: @@ -740,13 +756,17 @@ def peirce_decomposition(self): generated by {} over Rational Field, Free module generated by {0, 1} over Rational Field, Free module generated by {0} over Rational Field] - """ import itertools - decomp = [] - for (ei, ej) in itertools.product(self.orthogonal_idempotents_central_mod_rad(), repeat=2): - decomp.append(self.peirce_summand(ei, ej)) - return decomp + if list_idempotents is None: + list_idempotents = self.orthogonal_idempotents_central_mod_rad() + if check: + if not (all(e*e == e for e in list_idempotents) and + all(e*f == f*e and e*f == 0 for e, f in + itertools.product(list_idempotents, repeat=2) if e != f)): + raise ValueError("Not an orthogonal list of idempotents.") + return [self.peirce_summand(ei, ej) for ei, ej in + itertools.product(list_idempotents, repeat=2)] class ElementMethods: diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 65c676ecb9a..2abbce6dacb 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -92,7 +92,7 @@ def radical_basis(self, **keywords): - ``keywords`` -- for compatibility; ignored. - OUTPUT: the empty list since this algebra is semisimple + OUTPUT: the empty list since this algebra is semisimple. EXAMPLES:: @@ -126,7 +126,7 @@ def central_orthogonal_idempotents(self): INPUT: - - ``self`` -- a semisimple algebra + - ``self`` -- a semisimple algebra. OUTPUT: @@ -176,31 +176,31 @@ def _orthogonal_decomposition(self, generators=None): INPUT: - ``self`` a finite dimensional semisimple commutative - algebra + algebra. - ``generators`` a list of generators of ``self``. By - default it will be the basis of ``self`` + default it will be the basis of ``self``. OUTPUT: - list of elements of ``self`` each generating a one - dimensional simple submodule of ``self`` in direct - sum with the others. The list is maximal in the sens - that no quasi-idempotent `e` can be decomposed as a - sum `e = e_1 + e_2` of quasi-idempotents elements. + dimensional simple submodule summand of ``self``. The + list is maximal in the sense that no quasi-idempotent + `e` can be decomposed as a sum `e = e_1 + e_2` of + quasi-idempotents elements. ALGORITHM: - A commutative semisimple algebra `A` is a direct - sum of dimension 1 sub-algebras thanks to Schur - Lemma. The algorithm is recursive a proceed in two - steps: + A commutative semisimple algebra `A` is a direct + sum of dimension 1 sub-algebras thanks to Schur + Lemma. The algorithm is recursive a proceed in two + steps: - 0. If `A` is of dimension 1, return a non zero - element. - 1. Find a generator `a \in A` such that the - morphism `x \mapsto ax` has at least two (right) - eigenspaces. - 2. Decompose both eigenspaces recursively. + 0. If `A` is of dimension 1, return a non zero + element. + 1. Find a generator `a \in A` such that the + morphism `x \mapsto ax` has at least two (right) + eigenspaces. + 2. Decompose both eigenspaces recursively. EXAMPLES:: @@ -261,15 +261,19 @@ def rec(space, generators): @cached_method def central_orthogonal_idempotents(self): r""" - Return the minimum set of central orthogonal idempotents of ``self``. + Return the set of central orthogonal idempotents of ``self``. INPUT: - - ``self`` a commutative semisimple algebra + - ``self`` a commutative semisimple algebra. OUTPUT: - - list of idempotents of ``self`` + - list of central orthogonal idempotents of ``self``. + + .. NOTE:: + + All idempotents returned are primitive. EXAMPLES:: From c2942ce1b9982f0e9cc4f3158cad641cc5d3fd7e Mon Sep 17 00:00:00 2001 From: David Einstein Date: Tue, 21 Apr 2015 18:55:11 -0400 Subject: [PATCH 427/665] Temporary commit while I figure out what went wrong --- src/sage/combinat/tableau.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 0cc8b8fe065..c47fd74103e 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5368,10 +5368,10 @@ def cardinality(self): sage: SemistandardTableaux([3,2,1], max_entry=7).cardinality() 2352 """ - c = 0 - for comp in IntegerVectors(sum(self.shape), self.max_entry): - c += SemistandardTableaux_shape_weight(self.shape, Composition(comp)).cardinality() - return c + from sage.combinat.partition import Partitions + number = prod((self.max_entry + self.shape.content(*c)) / self.shape.hook_length(*c) + for c in self.shape.cells()) + return Integer(number) class SemistandardTableaux_shape_weight(SemistandardTableaux_shape): r""" From 78671017d905c8a5a67f4855a3b2acf74edf370c Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 21 Apr 2015 21:08:00 -0400 Subject: [PATCH 428/665] restored older _self_to_m in H basis, covered t=0 separately using hall-littlewood Qp --- src/sage/combinat/sf/classical.py | 2 +- src/sage/combinat/sf/macdonald.py | 112 +++++++++++++++++++++++++++--- 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index ca0fec9551f..d3cb6efad83 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -253,7 +253,7 @@ def _element_constructor_(self, x): return self(sx) elif isinstance(x, (macdonald.MacdonaldPolynomials_h.Element,macdonald.MacdonaldPolynomials_ht.Element)): H = x.parent() - sx = H._s._from_cache(x, H._s_cache, H._self_to_s_cache, q=H.q, t=H.t) + sx = H._self_to_s(x) return self(sx) elif isinstance(x, macdonald.MacdonaldPolynomials_s.Element): S = x.parent() diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 094af9682e2..2eb58784076 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1189,7 +1189,8 @@ def self_to_s(self, x): r""" Convert an element of either the ``H`` or ``Ht`` basis to the Schur basis - This function is here to force the coercion path to the Schur basis. + This function is here to force the coercion path to the Schur basis + because these bases are computed using their monomial expansion. INPUT: @@ -1215,7 +1216,8 @@ def s_to_self( self, x ): r""" Convert an element of either the Schur basis to either the ``H`` or ``Ht`` basis - This function is here to force the coercion path from the Schur basis. + This function is here to force the coercion path from the Schur basis + because these bases are computed using the monomial expansion. INPUT: @@ -1263,14 +1265,96 @@ def __init__(self, macdonald): MacdonaldPolynomials_generic.__init__(self, macdonald) self._m = self._sym.m() self._Lmunu = macdonald.Ht()._Lmunu + if not self.t: + self._Qp = self._sym.hall_littlewood(t=self.q).Qp() category = ModulesWithBasis(self.base_ring()) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) - _self_to_s = self_to_s - _s_to_self = s_to_self + def _self_to_s(self, x): + r""" + Return an element ``x`` of ``self`` expanded in the Schur basis. + + If `t=0` then the expression for `H_\mu[X;q,0]` is equal to + `\omega Q'_{\mu'}[X;q]` where `Q'` is the Hall-Littlewood basis. + + If `t \neq 0` then the conversion uses the monomial basis. + + INPUT: + + - ``x`` -- an element of ``H`` basis + + OUTPUT: + + - an element of the Schur basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) + sage: H = Sym.macdonald().H() + sage: s = Sym.s() + sage: s(H[2,1]) + q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3] + sage: H2 = Sym.macdonald(t=0).H() + sage: s(H2[2,1]) + q*s[1, 1, 1] + s[2, 1] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: H = Sym.macdonald(q=x,t=1/x).H() + sage: s = Sym.s() + sage: s(H[2,1]) + x*s[1, 1, 1] + 2*s[2, 1] + 1/x*s[3] + """ + if self.t: + return self_to_s(self, x) + else: + return sum(cmu*self._s(self._Qp(mu.conjugate())) for mu,cmu in x).omega() + + def _s_to_self(self, x): + r""" + Return an element of the Schur basis ``x`` expanded in the ``H`` basis. + + If `t=0` then the expression for `H_\mu[X;q,0]` is equal to + `\omega Q'_{\mu'}[X;q]` where `Q'` is the Hall-Littlewood basis. + + If `t \neq 0` then the conversion uses the monomial basis. + + INPUT: + + - ``x`` -- an element of the Schur basis + + OUTPUT: + + - an element of the ``H`` basis + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q','t'])) + sage: H = Sym.macdonald().H() + sage: s = Sym.s() + sage: H(s[1,1]) + -(1/(q*t-1))*McdH[1, 1] + (t/(q*t-1))*McdH[2] + sage: (q,t) = Sym.base_ring().gens() + sage: H(q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3]) + McdH[2, 1] + sage: H2 = Sym.macdonald(t=0).H() + sage: H2(q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3]) + (-q^2*t+1)*McdH[2, 1] + t*McdH[3] + + sage: Sym = SymmetricFunctions(FractionField(QQ['x'])) + sage: x = Sym.base_ring().gen() + sage: H = Sym.macdonald(q=x,t=1/x).H() + sage: s = Sym.s() + sage: H(x*s[1, 1, 1] + 2*s[2, 1] + 1/x*s[3]) + McdH[2, 1] + """ + if self.t: + return s_to_self(self, x) + else: + return self._from_dict({mu.conjugate() : cmu for mu,cmu in self._Qp(x.omega())}) def _self_to_m(self, x): r""" @@ -1298,13 +1382,21 @@ def _self_to_m(self, x): sage: m = Sym.m() sage: m(H[2,1]) ((x^2+4*x+1)/x)*m[1, 1, 1] + ((2*x+1)/x)*m[2, 1] + 1/x*m[3] + sage: H2 = Sym.macdonald(q=x,t=1).H() + sage: H2((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) + McdH[2, 1] + sage: H3 = Sym.macdonald(q=x,t=0).H() + sage: H3((3*x+3)*m[1, 1, 1] + (x+2)*m[2, 1] + m[3]) + (-x^2+1)*McdH[2, 1] + McdH[3] """ - (q,t)=QQqt.gens() - return self._m._from_dict({ part2: - self._base(sum(x.coefficient(mu)* (QQqt(self._Lmunu(part2, mu)).subs(t=1/t)* - t**mu.weighted_size()).subs(q=self.q,t=self.t) - for mu in x.homogeneous_component(d).support())) - for d in range(x.degree()+1) for part2 in Partitions(d) }) + if self.t: + return self._m._from_dict({ part2: + self._base(sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, + mu)).subs(q=self.q,t=1/self.t) * self.t**mu.weighted_size() + for mu in x.homogeneous_component(d).support())) + for d in range(x.degree()+1) for part2 in Partitions(d) }) + else: + return self._m(self._self_to_s(x)) def _m_to_self( self, f ): r""" From b1e92f40a5771d11c6e6244a7c68c55a58672eaf Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 21 Apr 2015 21:22:03 -0400 Subject: [PATCH 429/665] readjusted _self_to_s and _s_to_self in Ht and H bases --- src/sage/combinat/sf/macdonald.py | 108 ++++++++++++++---------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 2eb58784076..05a371fa272 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1185,61 +1185,6 @@ def _to_s(self, part): class Element(MacdonaldPolynomials_generic.Element): pass -def self_to_s(self, x): - r""" - Convert an element of either the ``H`` or ``Ht`` basis to the Schur basis - - This function is here to force the coercion path to the Schur basis - because these bases are computed using their monomial expansion. - - INPUT: - - - ``self`` - either a ``H`` or an ``Ht`` Macdonald basis - - ``x`` - an element of ``self`` - - OUTPUT: - - - an element of the Schur basis - - EXAMPLES:: - - sage: Ht = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().Ht() - sage: sage.combinat.sf.macdonald.self_to_s(Ht, Ht[2,1]) - q*t*s[1, 1, 1] + (q+t)*s[2, 1] + s[3] - sage: H = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().H() - sage: sage.combinat.sf.macdonald.self_to_s(H, H[2,1]) - q*s[1, 1, 1] + (q*t+1)*s[2, 1] + t*s[3] - """ - return self._s(self._self_to_m(x)) - -def s_to_self( self, x ): - r""" - Convert an element of either the Schur basis to either the ``H`` or ``Ht`` basis - - This function is here to force the coercion path from the Schur basis - because these bases are computed using the monomial expansion. - - INPUT: - - - ``self`` - either a ``H`` or an ``Ht`` Macdonald basis - - ``x`` - an element of ``s`` basis - - OUTPUT: - - - an element of the basis ``self`` - - EXAMPLES:: - sage: s = SymmetricFunctions(FractionField(QQ['q','t'])).s() - sage: Ht = s.symmetric_function_ring().macdonald().Ht() - sage: sage.combinat.sf.macdonald.s_to_self(Ht, s[2]) - ((-q)/(-q+t))*McdHt[1, 1] + (t/(-q+t))*McdHt[2] - sage: H = s.symmetric_function_ring().macdonald().H() - sage: sage.combinat.sf.macdonald.s_to_self(H, s[2]) - (q/(q*t-1))*McdH[1, 1] - (1/(q*t-1))*McdH[2] - """ - return self._m_to_self(self._m(x)) - - class MacdonaldPolynomials_h(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" @@ -1309,7 +1254,7 @@ def _self_to_s(self, x): x*s[1, 1, 1] + 2*s[2, 1] + 1/x*s[3] """ if self.t: - return self_to_s(self, x) + return self._s(self._self_to_m(x)) else: return sum(cmu*self._s(self._Qp(mu.conjugate())) for mu,cmu in x).omega() @@ -1352,7 +1297,7 @@ def _s_to_self(self, x): McdH[2, 1] """ if self.t: - return s_to_self(self, x) + return self._m_to_self(self._m(x)) else: return self._from_dict({mu.conjugate() : cmu for mu,cmu in self._Qp(x.omega())}) @@ -1489,8 +1434,53 @@ def __init__(self, macdonald): self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) - _self_to_s = self_to_s - _s_to_self = s_to_self + def _self_to_s(self, x): + r""" + Convert an element of the ``Ht`` basis to the Schur basis + + This function is here to force the coercion path to the Schur basis + because these bases are computed using their monomial expansion. + + INPUT: + + - ``x`` - an element of ``self`` + + OUTPUT: + + - an element of the Schur basis + + EXAMPLES:: + + sage: Ht = SymmetricFunctions(FractionField(QQ['q','t'])).macdonald().Ht() + sage: s = Ht.symmetric_function_ring().s() + sage: Ht._self_to_s(Ht[2,1]) + q*t*s[1, 1, 1] + (q+t)*s[2, 1] + s[3] + """ + return self._s(self._self_to_m(x)) + + def _s_to_self( self, x ): + r""" + Convert an element of either the Schur basis to the ``Ht`` basis + + This function is here to force the coercion path from the Schur basis + because these bases are computed using the monomial expansion. + + INPUT: + + - ``x`` - an element of ``s`` basis + + OUTPUT: + + - an element of the basis ``self`` + + EXAMPLES:: + + sage: s = SymmetricFunctions(FractionField(QQ['q','t'])).s() + sage: Ht = s.symmetric_function_ring().macdonald().Ht() + sage: Ht._s_to_self(s[2]) + ((-q)/(-q+t))*McdHt[1, 1] + (t/(-q+t))*McdHt[2] + """ + return self._m_to_self(self._m(x)) def _Lmunu(self, nu, mu ): r""" From 59394c6119e33ab5faa37ff4538643ab64f724b8 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 21 Apr 2015 21:48:50 -0400 Subject: [PATCH 430/665] corrected reference to rational polynomials --- src/sage/combinat/sf/macdonald.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 05a371fa272..37fab72dc3e 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -646,7 +646,7 @@ def cmunu1(mu, nu): OUTPUT: - - a rational polynomial in `q` and `t` + - an element of the fraction field of polynomials in `q` and `t` EXAMPLES:: @@ -696,7 +696,7 @@ def cmunu(mu, nu): OUTPUT: - - a rational polynomial in `q` and `t` + - an element of the fraction field of polynomials in `q` and `t` EXAMPLES:: From 811a7975d60133f5bd9e69be251982f04939f5a8 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 22 Apr 2015 04:15:51 +0200 Subject: [PATCH 431/665] fix two hash docstrings --- src/sage/combinat/rooted_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index c28a0b06fe1..f21388ee64e 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -257,7 +257,7 @@ def __hash__(self): sage: RT = RootedTree sage: hash(RT([[],[[]]])) # indirect doctest - 2578595415271398032 + 1119083152 """ return hash(self.sort_key()) @@ -889,7 +889,7 @@ def __hash__(self): sage: lb = RootedTrees()([[],[[], []]]).canonical_labelling() sage: hash(lb) # indirect doctest - 686798862222558969 + 652936953 """ return hash(self.sort_key()) From dc8120fd74f1d65a812e96c33afc9a8ca9a0bc8e Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Wed, 22 Apr 2015 08:40:59 +0200 Subject: [PATCH 432/665] new attempt at fixing doctests, can only check 32bit --- src/sage/combinat/rooted_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index f21388ee64e..5bc8ee41f9f 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -257,7 +257,8 @@ def __hash__(self): sage: RT = RootedTree sage: hash(RT([[],[[]]])) # indirect doctest - 1119083152 + 2578595415271398032 # 64-bit + 1119083152 # 32-bit """ return hash(self.sort_key()) @@ -889,7 +890,8 @@ def __hash__(self): sage: lb = RootedTrees()([[],[[], []]]).canonical_labelling() sage: hash(lb) # indirect doctest - 652936953 + 686798862222558969 # 64-bit + 652936953 # 32-bit """ return hash(self.sort_key()) From d4c53ac38372916a2e81100e2c4dd360b5afcf51 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 22 Apr 2015 10:26:22 +0200 Subject: [PATCH 433/665] Coercion for numpy types --- src/sage/rings/complex_double.pyx | 66 +++++++- src/sage/rings/integer.pyx | 25 ++- src/sage/rings/integer_ring.pyx | 19 +++ .../polynomial/polynomial_real_mpfr_dense.pyx | 20 +++ src/sage/rings/rational.pyx | 28 +++- src/sage/rings/real_double.pyx | 36 ++++- src/sage/rings/real_mpfi.pyx | 16 ++ src/sage/structure/coerce.pxd | 2 +- src/sage/structure/coerce.pyx | 152 ++++++++++++++++-- src/sage/symbolic/function.pyx | 4 +- src/sage/symbolic/ring.pyx | 74 +++++++-- 11 files changed, 396 insertions(+), 46 deletions(-) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 5a735e7320e..ebd4973d4ca 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -81,6 +81,7 @@ from sage.structure.element cimport RingElement, Element, ModuleElement, FieldEl from sage.structure.parent cimport Parent from sage.structure.parent_gens import ParentWithGens from sage.categories.morphism cimport Morphism +from sage.structure.coerce cimport is_numpy_type from sage.libs.pari.gen cimport gen as pari_gen from sage.libs.pari.pari_instance cimport PariInstance @@ -402,20 +403,29 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): sage: CDF.has_coerce_map_from(complex) True """ - from integer_ring import ZZ + if S is int or S is float: + return FloatToCDF(S) from rational_field import QQ from real_lazy import RLF from real_mpfr import RR, RealField_class from complex_field import ComplexField, ComplexField_class CC = ComplexField() from complex_number import CCtoCDF - if S in [int, float, ZZ, QQ, RDF, RLF]: + if S is ZZ or S is QQ or S is RDF or S is RLF: return FloatToCDF(S) if isinstance(S, RealField_class): if S.prec() >= 53: return FloatToCDF(S) else: return None + elif is_numpy_type(S): + import numpy + if issubclass(S, numpy.integer) or issubclass(S, numpy.floating): + return FloatToCDF(S) + elif issubclass(S, numpy.complexfloating): + return ComplexToCDF(S) + else: + return None elif RR.has_coerce_map_from(S): return FloatToCDF(RR) * RR._internal_coerce_map_from(S) elif isinstance(S, ComplexField_class) and S.prec() >= 53: @@ -2410,7 +2420,7 @@ cdef class ComplexDoubleElement(FieldElement): cdef class FloatToCDF(Morphism): """ - Fast morphism from anything with a ``__float__`` method to an RDF element. + Fast morphism from anything with a ``__float__`` method to a CDF element. EXAMPLES:: @@ -2438,6 +2448,7 @@ cdef class FloatToCDF(Morphism): To: Complex Double Field sage: f(3.5) 3.5 + """ def __init__(self, R): """ @@ -2484,6 +2495,55 @@ cdef class FloatToCDF(Morphism): """ return "Native" + +cdef class ComplexToCDF(Morphism): + r""" + Fast morphism for anything such that the elements have attributes ``.real`` + and ``.imag`` (e.g. numpy complex types). + + EXAMPLES:: + + sage: import numpy + sage: f = CDF.coerce_map_from(numpy.complex_) + sage: f(numpy.complex_(1jr)) + 1.0*I + sage: f(numpy.complex_(1jr)).parent() + Complex Double Field + """ + def __init__(self, R): + from sage.categories.homset import Hom + if isinstance(R, type): + from sage.structure.parent import Set_PythonType + R = Set_PythonType(R) + Morphism.__init__(self, Hom(R, CDF)) + + cpdef Element _call_(self, x): + """ + Create an :class:`ComplexDoubleElement`. + + EXAMPLES:: + + sage: import numpy + sage: CDF(numpy.complex_(1jr)) # indirect doctest + 1.0*I + """ + cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) + z._complex = gsl_complex_rect(x.real, x.imag) + return z + + def _repr_type(self): + """ + Return string that describes the type of morphism. + + EXAMPLES:: + + sage: import numpy + sage: f = sage.rings.complex_double.ComplexToCDF(numpy.complex_) + sage: f._repr_type() + 'Native' + """ + return "Native" + ##################################################### # Create new ComplexDoubleElement from a # gsl_complex C struct. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index e8098262416..388009e27bc 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -166,6 +166,7 @@ import sage.rings.infinity import sage.libs.pari.pari_instance cdef PariInstance pari = sage.libs.pari.pari_instance.pari +from sage.structure.coerce cimport is_numpy_type from sage.structure.element import canonical_coercion, coerce_binop cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 else '=i8' } @@ -589,6 +590,19 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): True sage: a == ZZ(L,base=2^64) True + + Test comparisons with numpy types (see :trac:`13386` and :trac:`18076`):: + + sage: import numpy + sage: numpy.int8('12') == 12 + True + sage: 12 == numpy.int8('12') + True + + sage: numpy.float('15') == 15 + True + sage: 15 == numpy.float('15') + True """ # TODO: All the code below should somehow be in an external # cdef'd function. Then e.g., if a matrix or vector or @@ -676,12 +690,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set(self.value, tmp.value) return - import numpy - if isinstance(x, numpy.integer): - mpz_set_pylong(self.value, x.__long__()) - return + elif is_numpy_type(type(x)): + import numpy + if isinstance(x, numpy.integer): + mpz_set_pylong(self.value, x.__long__()) + return - raise TypeError, "unable to coerce %s to an integer" % type(x) + raise TypeError("unable to coerce %s to an integer" % type(x)) def __reduce__(self): """ diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index c88b6b34948..d327f32f601 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -59,6 +59,7 @@ import sage.libs.pari.all import sage.rings.ideal from sage.categories.basic import EuclideanDomains from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.structure.coerce cimport is_numpy_type from sage.structure.parent_gens import ParentWithGens from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence @@ -603,6 +604,18 @@ cdef class IntegerRing_class(PrincipalIdealDomain): ... TypeError: no canonical coercion from Rational Field to Integer Ring + Coercions are available from numpy integer types:: + + sage: import numpy + sage: ZZ.coerce(numpy.int8('1')) + 1 + sage: ZZ.coerce(numpy.int32('32')) + 32 + sage: ZZ.coerce(numpy.int64('-12')) + -12 + sage: ZZ.coerce(numpy.uint64('11')) + 11 + TESTS:: sage: 5r + True @@ -633,6 +646,12 @@ cdef class IntegerRing_class(PrincipalIdealDomain): return sage.rings.integer.long_to_Z() elif S is bool: return True + elif is_numpy_type(S): + import numpy + if issubclass(S, numpy.integer): + return True + else: + return None else: None diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 1929f2a904c..d833d270575 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -1,5 +1,25 @@ r""" Dense univariate polynomials over `\RR`, implemented using MPFR + +TESTS: + +Check that operations with numpy elements work well (see :trac:`18076` and +:trac:`8426`):: + + sage: import numpy + sage: x = polygen(RR) + sage: x * numpy.int32('1') + x + sage: numpy.int32('1') * x + x + sage: x * numpy.int64('1') + x + sage: numpy.int64('1') * x + x + sage: x * numpy.float32('1.5') + 1.50000000000000*x + sage: numpy.float32('1.5') * x + 1.50000000000000*x """ include "sage/ext/stdsage.pxi" diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index b7c38e071fd..fe70c7c6f09 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -68,6 +68,7 @@ from sage.libs.pari.pari_instance cimport PariInstance, INT_to_mpz, INTFRAC_to_m from integer_ring import ZZ from sage.libs.gmp.rational_reconstruction cimport mpq_rational_reconstruction +from sage.structure.coerce cimport is_numpy_type from sage.structure.element cimport Element, RingElement, ModuleElement from sage.structure.element import bin_op, coerce_binop from sage.categories.morphism cimport Morphism @@ -352,6 +353,21 @@ cdef class Rational(sage.structure.element.FieldElement): -939082/3992923 sage: Rational(pari('Pol([-1/2])')) #9595 -1/2 + + Conversions from numpy:: + + sage: import numpy as np + sage: QQ(np.int8('-15')) + -15 + sage: QQ(np.int16('-32')) + -32 + sage: QQ(np.int32('-19')) + -19 + sage: QQ(np.uint32('1412')) + 1412 + + sage: QQ(np.float16('12')) + 12 """ def __cinit__(self): r""" @@ -542,9 +558,17 @@ cdef class Rational(sage.structure.element.FieldElement): elif isinstance(x, (float, sage.rings.real_double.RealDoubleElement)): self.__set_value(sage.rings.real_mpfr.RealNumber(sage.rings.real_mpfr.RR, x), base) - else: + elif is_numpy_type(type(x)): + import numpy + if isinstance(x, numpy.integer): + self.__set_value(integer.Integer(x), base) + elif isinstance(x, numpy.floating): + self.__set_value(sage.rings.real_double.RDF(x), base) + else: + raise TypeError("Unable to coerce {} ({}) to Rational".format(x,type(x))) - raise TypeError, "Unable to coerce %s (%s) to Rational"%(x,type(x)) + else: + raise TypeError("Unable to coerce {} ({}) to Rational".format(x,type(x))) cdef void set_from_mpq(Rational self, mpq_t value): mpq_set(self.value, value) diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 1bfe048b212..a2c3413d8ff 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -64,6 +64,8 @@ from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.categories.morphism cimport Morphism +from sage.structure.coerce cimport is_numpy_type + def is_RealDoubleField(x): """ @@ -288,8 +290,9 @@ cdef class RealDoubleField_class(Field): - the real double field itself - int, long, integer, and rational rings - - real mathematical constants - - the MPFR real field with at most 53 bits of precision + - numpy integers and floatings + - the real lazy field + - the MPFR real field with at least 53 bits of precision EXAMPLES:: @@ -307,13 +310,38 @@ cdef class RealDoubleField_class(Field): 5.0 + 1.0*I sage: RLF(2/3) + RDF(1) 1.6666666666666665 + + sage: import numpy + sage: RDF.coerce(numpy.int8('1')) + 1.0 + sage: RDF.coerce(numpy.float64('1')) + 1.0 + + sage: RDF.coerce(pi) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Symbolic Ring to Real Double Field + + Test that :trac:`15965` is fixed (see also :trac:`18076`):: + + sage: 1j + numpy.float64(2) + 2.00000000000000 + 1.00000000000000*I + sage: parent(_) + Complex Field with 53 bits of precision """ - from integer_ring import ZZ + if S is int or S is float: + return ToRDF(S) from rational_field import QQ from real_lazy import RLF from real_mpfr import RR, RealField_class - if S in [int, float, ZZ, QQ, RLF] or isinstance(S, RealField_class) and S.prec() >= 53: + if S is ZZ or S is QQ or S is RLF or (isinstance(S, RealField_class) and S.prec() >= 53): return ToRDF(S) + elif is_numpy_type(S): + import numpy + if issubclass(S, numpy.integer) or issubclass(S, numpy.floating): + return ToRDF(S) + else: + return None connecting = RR._internal_coerce_map_from(S) if connecting is not None: return ToRDF(RR) * connecting diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 24a1bac50b9..863d3275a07 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -209,6 +209,22 @@ interval coerces to plus infinity:: sage: RIF(-oo,oo) == oo True + +TESTS: + +Comparisons with numpy types are right (see :trac:`17758` and :trac:`18076`):: + + sage: import numpy + sage: RIF(0,1) < numpy.float('2') + True + sage: RIF(0,1) <= numpy.float('1') + True + sage: RIF(0,1) <= numpy.float('0.5') + False + sage: RIF(2) == numpy.int8('2') + True + sage: numpy.int8('2') == RIF(2) + True """ #***************************************************************************** diff --git a/src/sage/structure/coerce.pxd b/src/sage/structure/coerce.pxd index 117c25a6840..07103449788 100644 --- a/src/sage/structure/coerce.pxd +++ b/src/sage/structure/coerce.pxd @@ -1,4 +1,3 @@ - from element cimport Element, RingElement, ModuleElement, CoercionModel from parent cimport Parent @@ -8,6 +7,7 @@ from coerce_dict cimport TripleDict cpdef py_scalar_parent(py_type) cpdef py_scalar_to_element(py) +cpdef bint is_numpy_type(t) cdef class CoercionModel_cache_maps(CoercionModel): # This MUST be a mapping to tuples, where each diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6f7dae6fc24..fe8ec25204f 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -74,6 +74,7 @@ see the documentation for Parent. #***************************************************************************** from cpython.object cimport * +from libc.string cimport strncmp cdef add, sub, mul, div, iadd, isub, imul, idiv import operator @@ -117,16 +118,45 @@ cpdef py_scalar_parent(py_type): Integer Ring sage: py_scalar_parent(dict), (None,) + + sage: import numpy + sage: py_scalar_parent(numpy.int16) + Integer Ring + sage: py_scalar_parent(numpy.int32) + Integer Ring + sage: py_scalar_parent(numpy.uint64) + Integer Ring + + sage: py_scalar_parent(numpy.float) + Real Double Field + sage: py_scalar_parent(numpy.double) + Real Double Field + + sage: py_scalar_parent(numpy.complex) + Complex Double Field """ - if py_type is int or py_type is long or py_type is bool: + if issubclass(py_type, int) or issubclass(py_type, long) or issubclass(py_type, bool): import sage.rings.integer_ring return sage.rings.integer_ring.ZZ - elif py_type is float: + elif issubclass(py_type, float): import sage.rings.real_double return sage.rings.real_double.RDF - elif py_type is complex: + elif issubclass(py_type, complex): import sage.rings.complex_double return sage.rings.complex_double.CDF + elif is_numpy_type(py_type): + import numpy + if issubclass(py_type, numpy.integer): + import sage.rings.integer_ring + return sage.rings.integer_ring.ZZ + elif issubclass(py_type, numpy.floating): + import sage.rings.real_double + return sage.rings.real_double.RDF + elif issubclass(py_type, numpy.complexfloating): + import sage.rings.complex_double + return sage.rings.complex_double.CDF + else: + return None else: return None @@ -169,6 +199,17 @@ cpdef py_scalar_to_element(x): sage: elt = [True, int(42), long(42), float(42), complex(42)] sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() + + sage: import numpy + sage: elt = [numpy.int8('-12'), numpy.uint8('143'), + ....: numpy.int16('-33'), numpy.uint16('122'), + ....: numpy.int32('-19'), numpy.uint32('44'), + ....: numpy.int64('-3'), numpy.uint64('552'), + ....: numpy.float16('-1.23'), numpy.float32('-2.22'), + ....: numpy.float64('-3.412'), numpy.complex64(1.2+1jr), + ....: numpy.complex128(-2+.1jr)] + sage: for x in elt: + ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() """ if isinstance(x, Element): return x @@ -184,12 +225,51 @@ cpdef py_scalar_to_element(x): elif isinstance(x, complex): from sage.rings.complex_double import CDF return CDF(x) + elif is_numpy_type(type(x)): + import numpy + if isinstance(x, numpy.integer): + from sage.rings.integer import Integer + return Integer(x) + elif isinstance(x, numpy.floating): + from sage.rings.real_double import RDF + return RDF(x) + elif isinstance(x, numpy.complexfloating): + from sage.rings.complex_double import CDF + return CDF(x) + else: + return x else: return x -cdef _native_coercion_ranks_inv = (bool, int, long, float, complex) -cdef dict _native_coercion_ranks = dict([(t, k) for k, t in enumerate(_native_coercion_ranks_inv)]) +cpdef bint is_numpy_type(t): + """ + Return ``True`` if and only if `t` is a type whose name starts + with ``numpy.`` + + EXAMPLES:: + + sage: from sage.structure.coerce import is_numpy_type + sage: import numpy + sage: is_numpy_type(numpy.int16) + True + sage: is_numpy_type(numpy.floating) + True + sage: is_numpy_type(numpy.float) # Alias for Python float + False + sage: is_numpy_type(int) + False + sage: is_numpy_type(Integer) + False + sage: is_numpy_type(Sudoku) + False + sage: is_numpy_type(None) + False + """ + if not isinstance(t, type): + return False + return strncmp((t).tp_name, "numpy.", 6) == 0 + cdef object _Integer cdef bint is_Integer(x): @@ -220,6 +300,45 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: ZZ['x,y,z'].0 + ZZ['w,x,z,a'].1 2*x + TESTS: + + Check that :trac:`8426` is fixed (see also :trac:`18076`):: + + sage: import numpy + sage: x = polygen(RR) + sage: numpy.float32('1.5') * x + 1.50000000000000*x + sage: x * numpy.float32('1.5') + 1.50000000000000*x + sage: p = x**3 + 2*x - 1 + sage: p(numpy.float('1.2')) + 3.12800000000000 + sage: p(numpy.int('2')) + 11.0000000000000 + + This used to fail (see :trac:`18076`):: + + sage: 1/3 + numpy.int8('12') + 37/3 + sage: -2/3 + numpy.int16('-2') + -8/3 + sage: 2/5 + numpy.uint8('2') + 12/5 + + The numpy types do not interact well with the Sage coercion framework. More + precisely, if a numpy type is the first operand in a binary operation then + this operation is done in numpy. The result is hence a numpy type:: + + sage: numpy.uint8('2') + 3 + 5 + sage: type(_) + + + sage: numpy.int8('12') + 1/3 + 12.333333333333334 + sage: type(_) + + AUTHOR: - Robert Bradshaw @@ -976,9 +1095,9 @@ cdef class CoercionModel_cache_maps(CoercionModel): else: y_elt = y if x_elt is None: - raise RuntimeError, "BUG in map, returned None %s %s %s" % (x, type(x_map), x_map) + raise RuntimeError("BUG in map, returned None %s %s %s" % (x, type(x_map), x_map)) elif y_elt is None: - raise RuntimeError, "BUG in map, returned None %s %s %s" % (y, type(y_map), y_map) + raise RuntimeError("BUG in map, returned None %s %s %s" % (y, type(y_map), y_map)) if x_elt._parent is y_elt._parent: # We must verify this as otherwise we are prone to # getting into an infinite loop in c, and the above @@ -995,13 +1114,18 @@ cdef class CoercionModel_cache_maps(CoercionModel): cdef bint x_numeric = isinstance(x, (int, long, float, complex)) cdef bint y_numeric = isinstance(y, (int, long, float, complex)) + if not x_numeric and is_numpy_type(type(x)): + import numpy + x_numeric = isinstance(x, numpy.number) + if not y_numeric and is_numpy_type(type(y)): + import numpy + y_numeric = isinstance(y, numpy.number) + if x_numeric and y_numeric: - x_rank = _native_coercion_ranks[type(x)] - y_rank = _native_coercion_ranks[type(y)] - ty = _native_coercion_ranks_inv[max(x_rank, y_rank)] - x = ty(x) - y = ty(y) - return x, y + ty = type(x + y) + if ty != type(y + x): + raise RuntimeError("x + y and y + x have different types for x={} ({}) and y={} ({})".format(x, type(x), y, type(y))) + return ty(x), ty(y) # Now handle the native python + sage object cases # that were not taken care of above. @@ -1048,7 +1172,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): except Exception: self._record_exception() - raise TypeError, "no common canonical parent for objects with parents: '%s' and '%s'"%(xp, yp) + raise TypeError("no common canonical parent for objects with parents: '%s' and '%s'"%(xp, yp)) cpdef coercion_maps(self, R, S): diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index c87b941f296..bf8a913d6df 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -21,7 +21,7 @@ from sage.structure.element cimport Element, parent_c from expression cimport new_Expression_from_GEx, Expression from ring import SR -from sage.structure.coerce cimport py_scalar_to_element +from sage.structure.coerce cimport py_scalar_to_element, is_numpy_type from sage.structure.element import get_coercion_model # we keep a database of symbolic functions initialized in a session @@ -421,7 +421,7 @@ cdef class Function(SageObject): return method() # support numpy arrays as arguments - if any([type(arg).__module__ == 'numpy' for arg in args]): # avoid importing + if any([is_numpy_type(type(arg)) for arg in args]): import numpy # check that at least one of the arguments is a numpy array if any([isinstance(arg, numpy.ndarray) for arg in args]): diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 247bba3f65c..83841c22b72 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -31,6 +31,7 @@ from sage.structure.element cimport RingElement, Element, Matrix from sage.structure.parent_base import ParentWithBase from sage.rings.ring cimport CommutativeRing from sage.categories.morphism cimport Morphism +from sage.structure.coerce cimport is_numpy_type from sage.rings.all import RR, CC @@ -119,7 +120,7 @@ cdef class SymbolicRing(CommutativeRing): TESTS: - Check if arithmetic with bools work #9560:: + Check if arithmetic with bools works (see :trac:`9560`):: sage: SR.has_coerce_map_from(bool) True @@ -136,14 +137,14 @@ cdef class SymbolicRing(CommutativeRing): if R in [int, float, long, complex, bool]: return True - if 'numpy' in R.__module__: + if is_numpy_type(R): import numpy - basic_types = [numpy.float, numpy.float32, numpy.float64, - numpy.complex, numpy.complex64, numpy.complex128] - if hasattr(numpy, 'float128'): - basic_types += [numpy.float128, numpy.complex256] - if R in basic_types: + if (issubclass(R, numpy.integer) or + issubclass(R, numpy.floating) or + issubclass(R, numpy.complexfloating)): return NumpyToSRMorphism(R, self) + else: + return None if 'sympy' in R.__module__: from sympy.core.basic import Basic @@ -793,6 +794,35 @@ cdef unsigned sage_domain_to_ginac(object domain) except +: raise ValueError("domain must be one of 'complex', 'real' or 'positive'") cdef class NumpyToSRMorphism(Morphism): + r""" + A morphism from numpy types to the symbolic ring. + + TESTS: + + We check that :trac:`8949` and :trac:`9769` are fixed (see also :trac:`18076`):: + + sage: import numpy + sage: f(x) = x^2 + sage: f(numpy.int8('2')) + 4 + sage: f(numpy.int32('3')) + 9 + + Note that the answer is a Sage integer and not a numpy type:: + + sage: a = f(numpy.int8('2')).pyobject() + sage: type(a) + + + This behavior also applies to standard functions:: + + sage: cos(numpy.int('2')) + cos(2) + sage: numpy.cos(numpy.int('2')) + -0.41614683654714241 + """ + cdef _intermediate_ring + def __init__(self, numpy_type, R): """ A Morphism which constructs Expressions from NumPy floats and @@ -812,6 +842,17 @@ cdef class NumpyToSRMorphism(Morphism): from sage.structure.parent import Set_PythonType Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(numpy_type), R)) + import numpy + if issubclass(numpy_type, numpy.integer): + from sage.rings.all import ZZ + self._intermediate_ring = ZZ + if issubclass(numpy_type, numpy.floating): + from sage.rings.all import RDF + self._intermediate_ring = RDF + elif issubclass(numpy_type, numpy.complexfloating): + from sage.rings.all import CDF + self._intermediate_ring = CDF + cpdef Element _call_(self, a): """ EXAMPLES: @@ -820,17 +861,20 @@ cdef class NumpyToSRMorphism(Morphism): float or complex to the Symbolic Ring:: sage: import numpy + sage: SR(numpy.int32('1')).pyobject().parent() + Integer Ring + sage: SR(numpy.int64('-2')).pyobject().parent() + Integer Ring + + sage: SR(numpy.float16('1')).pyobject().parent() + Real Double Field sage: SR(numpy.float64('2.0')).pyobject().parent() Real Double Field - """ - from sage.rings.all import RDF, CDF - numpy_type = self.domain().object() - if 'complex' in numpy_type.__name__: - res = CDF(a) - else: - res = RDF(a) - return new_Expression_from_pyobject(self.codomain(), res) + sage: SR(numpy.complex64(1jr)).pyobject().parent() + Complex Double Field + """ + return new_Expression_from_pyobject(self.codomain(), self._intermediate_ring(a)) cdef class UnderscoreSageMorphism(Morphism): def __init__(self, t, R): From 196e3959586577954c138b966986535793e46953 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 22 Apr 2015 11:04:07 +0200 Subject: [PATCH 434/665] Removed trailing whitespaces and changed LinearCode docstring --- src/sage/coding/linear_code.py | 36 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 684950d3311..f4fd1c0c00f 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -696,9 +696,9 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, class AbstractLinearCode(module.Module): """ Abstract class for linear codes. - + This class contains all methods that can be used on Linear Codes - and on Linear Codes families. + and on Linear Codes families. So, every Linear Code-related class should inherit from this abstract class. @@ -792,7 +792,7 @@ def __init__(self, base_field, length): raise an exception:: sage: C = CodeExample(GF(17), 10.0, 5, generator_matrix) - Traceback (most recent call last): + Traceback (most recent call last): ... ValueError: length must be a Python int or a Sage Integer """ @@ -1017,7 +1017,7 @@ def base_field(self): sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.base_field() - Finite Field of size 2 + Finite Field of size 2 """ return self.base_ring() @@ -1331,7 +1331,7 @@ def parity_check_matrix(self): r""" Returns the parity check matrix of ``self``. - The parity check matrix of a linear code `C` corresponds to the + The parity check matrix of a linear code `C` corresponds to the generator matrix of the dual code of `C`. EXAMPLES:: @@ -1803,7 +1803,7 @@ def __getitem__(self, i): return codeword def generator_matrix(self): - return NotImplementedError("This method must be set in subclasses") + return NotImplementedError("This method must be set in subclasses") def generator_matrix_systematic(self): """ @@ -2972,7 +2972,7 @@ def syndrome(self, r): Returns the syndrome of ``r``. The syndrome of ``r`` is the result of `H \times r` where `H` is - the parity check matrix of ``self``. If ``r`` belongs to ``self``, + the parity check matrix of ``self``. If ``r`` belongs to ``self``, its syndrome equals to the zero vector. INPUT: @@ -2982,13 +2982,13 @@ def syndrome(self, r): OUTPUT: - a column vector - + EXAMPLES:: sage: MS = MatrixSpace(GF(2),4,7) sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) - sage: r = vector(GF(2), (1,0,1,0,1,0,1)) + sage: r = vector(GF(2), (1,0,1,0,1,0,1)) sage: r in C True sage: C.syndrome(r) @@ -2996,7 +2996,7 @@ def syndrome(self, r): If ``r`` is not a codeword, its syndrome is not equal to zero:: - sage: r = vector(GF(2), (1,0,1,0,1,1,1)) + sage: r = vector(GF(2), (1,0,1,0,1,1,1)) sage: r in C False sage: C.syndrome(r) @@ -3214,13 +3214,19 @@ def LinearCodeFromVectorSpace(V, d=None): class LinearCode(AbstractLinearCode): r""" - Linear codes over a finite field or finite ring. + Linear codes over a finite field or finite ring, represented using a + generator matrix. + + This class should be used for arbitrary and unstructured linear codes. This + means that basic operations on the code, such as the computation of the + minimum distance, will use generic, slow algorithms. - A *linear code* is a subspace of a vector space over a finite field. It can - be defined by one of its basis or equivalently a generator matrix (a `k - \times n` matrix of full rank `k`). + If you are looking for constructing a code from a more specific family, see + if the family has been implemented by investigating codes.. These + more specific classes use properties particular for that family to allow + faster algorithms, and could also have family-specific methods. - See :wikipedia:`Linear_code` for more information. + See :wikipedia:`Linear_code` for more information on unstructured linear codes. INPUT: From db95e000594f8997731f92f11683cbf9c1241aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 22 Apr 2015 12:07:59 +0200 Subject: [PATCH 435/665] 18273: add category option to SymmetricGroup.algebra and Permutations.algebra for consistency --- src/sage/combinat/permutation.py | 18 ++++++++++++--- src/sage/combinat/symmetric_group_algebra.py | 22 ++++++++++++++---- src/sage/groups/perm_gps/permgroup_named.py | 24 ++++++++++++++++---- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index a6227e29721..aeda3d54eb0 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -6123,18 +6123,30 @@ def conjugacy_class(self, g): from sage.groups.perm_gps.symgp_conjugacy_class import PermutationsConjugacyClass return PermutationsConjugacyClass(self, g) - def algebra(self, base_ring): + def algebra(self, base_ring, category=None): """ Return the symmetric group algebra associated to ``self``. + INPUT: + + - ``base_ring`` -- a ring + - ``category`` -- a category (default: the category of ``self``) + EXAMPLES:: sage: P = Permutations(4) - sage: P.algebra(QQ) + sage: A = P.algebra(QQ); A Symmetric group algebra of order 4 over Rational Field + + sage: A.category() + Join of Category of coxeter group algebras over Rational Field + and Category of finite group algebras over Rational Field + sage: A = P.algebra(QQ, category=Monoids()) + sage: A.category() + Category of finite dimensional monoid algebras over Rational Field """ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra - return SymmetricGroupAlgebra(base_ring, self) + return SymmetricGroupAlgebra(base_ring, self, category=category) @cached_method def index_set(self): diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index a7d3ffc71b0..367f6bf6edc 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -29,7 +29,7 @@ # TODO: Remove this function and replace it with the class # TODO: Create parents for other bases (such as the seminormal basis) -def SymmetricGroupAlgebra(R, W): +def SymmetricGroupAlgebra(R, W, category=None): """ Return the symmetric group algebra of order ``W`` over the ring ``R``. @@ -37,6 +37,8 @@ def SymmetricGroupAlgebra(R, W): - ``W`` -- a symmetric group; alternatively an integer `n` can be provided, as shorthand for ``Permutations(n)``. + - ``R`` -- a base ring + - ``category`` -- a category (default: the category of ``W``) This supports several implementations of the symmetric group. At this point this has been tested with ``W=Permutations(n)`` and @@ -169,6 +171,15 @@ def SymmetricGroupAlgebra(R, W): for multiplying permutations (these methods don't depend on the setting). See :trac:`14885` for more information. + We conclude by constructing the algebra of the symmetric group as + a monoid algebra:: + + sage: QS3 = SymmetricGroupAlgebra(QQ, 3, category=Monoids()) + sage: QS3.category() + Category of finite dimensional monoid algebras over Rational Field + sage: TestSuite(QS3).run() + + TESTS:: sage: QS3 = SymmetricGroupAlgebra(QQ, 3) @@ -202,11 +213,13 @@ def SymmetricGroupAlgebra(R, W): from sage.rings.semirings.non_negative_integer_semiring import NN if W in NN: W = Permutations(W) - return SymmetricGroupAlgebra_n(R, W) + if category is None: + category = W.category() + return SymmetricGroupAlgebra_n(R, W, category.Algebras(R)) class SymmetricGroupAlgebra_n(CombinatorialFreeModule): - def __init__(self, R, W): + def __init__(self, R, W, category): """ TESTS:: @@ -243,9 +256,8 @@ def __init__(self, R, W): self.n = len(W.one().fixed_points()) else: self.n = W.cartan_type().rank() + 1 - cat = W.category().Algebras(R) CombinatorialFreeModule.__init__(self, R, W, prefix='', - latex_prefix='', category=cat) + latex_prefix='', category=category) def _repr_(self): """ diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 2a3a6f9c12b..d849fc4ab09 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -538,10 +538,15 @@ def conjugacy_class(self, g): from sage.groups.perm_gps.symgp_conjugacy_class import SymmetricGroupConjugacyClass return SymmetricGroupConjugacyClass(self, g) - def algebra(self, base_ring): + def algebra(self, base_ring, category=None): """ Return the symmetric group algebra associated to ``self``. + INPUT: + + - ``base_ring`` -- a ring + - ``category`` -- a category (default: the category of ``self``) + If ``self`` is the symmetric group on `1,\ldots,n`, then this is special cased to take advantage of the features in :class:`SymmetricGroupAlgebra`. Otherwise the usual group @@ -554,13 +559,24 @@ def algebra(self, base_ring): Symmetric group algebra of order 4 over Rational Field sage: S3 = SymmetricGroup([1,2,3]) - sage: S3.algebra(QQ) + sage: A = S3.algebra(QQ); A Symmetric group algebra of order 3 over Rational Field sage: a = S3.an_element(); a (1,2,3) - sage: S3.algebra(QQ)(a) + sage: A(a) (1,2,3) + We illustrate the choice of the category:: + + sage: A.category() + Join of Category of coxeter group algebras over Rational Field + and Category of finite group algebras over Rational Field + sage: A = S3.algebra(QQ, category=Semigroups()) + sage: A.category() + Category of finite dimensional semigroup algebras over Rational Field + + In the following case, a usual group algebra is returned: + sage: S = SymmetricGroup([2,3,5]) sage: S.algebra(QQ) Group algebra of Symmetric group of order 3! as a permutation group over Rational Field @@ -572,7 +588,7 @@ def algebra(self, base_ring): from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra domain = self.domain() if list(domain) == range(1, len(domain)+1): - return SymmetricGroupAlgebra(base_ring, self) + return SymmetricGroupAlgebra(base_ring, self, category=category) else: return super(SymmetricGroup, self).algebra(base_ring) From 934f6c58f0d9d5636f479e18869b852c8ce94686 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 22 Apr 2015 13:48:04 +0200 Subject: [PATCH 436/665] Moved random_error_position to prandom --- src/sage/coding/channel_constructions.py | 50 ++++++------------------ src/sage/misc/prandom.py | 34 ++++++++++++++++ 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 47de2668f41..c6d851df7b5 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -25,51 +25,24 @@ #***************************************************************************** from sage.rings.finite_rings.constructor import GF -from sage.misc.prandom import randint, random +from sage.misc.prandom import randint, random, random_error_position from sage.modules.free_module_element import vector from sage.misc.abstract_method import abstract_method from sage.combinat.cartesian_product import CartesianProduct from sage.modules.free_module import VectorSpace -def _random_error_position(n , number_errors): - r""" - Returns a list of exactly ``number_errors`` random numbers between 0 and ``n-1`` - This is a helper function, for internal use only. - This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. - - INPUT: - - - ``number_errors`` -- the number of elements in the list - - - ``n`` -- upper bound for the elements of the list - - OUTPUT: - - - A list of integers - - EXAMPLES:: - - sage: sage.coding.channel_constructions._random_error_position(6, 2) # random - [1, 4] - """ - error_position = [] - i = 0 - while i < n and number_errors > 0: - if random() < number_errors/(n-i): - error_position.append(i) - number_errors -= 1 - i += 1 - return error_position - def _random_error_vector(n, F, error_positions): r""" Return a vector of length ``n`` over ``F`` filled with random non-zero coefficients at the positions given by ``error_positions``. - This is a helper function, for internal use only. + This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) and was written by Johan Nielsen. + ..NOTE:: + + This is a helper function, which should only be used when implementing new channels. + INPUT: - ``n`` -- the length of the vector @@ -97,7 +70,10 @@ def _tuple_to_integer(value): r""" Returns an integer from ``value``. If ``value`` is a tuple, it will return a random integer between its bounds. - This is a helper function, for internal use only. + + ..NOTE:: + + This is a helper function, which should only be used when implementing new channels. INPUT: @@ -412,7 +388,7 @@ def transmit_unsafe(self, message): V = self.input_space() n = V.dimension() error_vector = _random_error_vector(n, V.base_ring(),\ - _random_error_position(n, number_errors)) + random_error_position(n, number_errors)) return message + error_vector def number_errors(self): @@ -608,9 +584,9 @@ def transmit_unsafe(self, message): V = self.input_space() n = V.dimension() - erroneous_positions = _random_error_position(n,\ + erroneous_positions = random_error_position(n,\ number_errors + number_erasures) - error_split = _random_error_position(number_errors + number_erasures,\ + error_split = random_error_position(number_errors + number_erasures,\ number_errors) error_positions = [ erroneous_positions[i] for i in\ range(number_errors + number_erasures) if i in error_split ] diff --git a/src/sage/misc/prandom.py b/src/sage/misc/prandom.py index 95b26c78cdf..d2d172a5464 100644 --- a/src/sage/misc/prandom.py +++ b/src/sage/misc/prandom.py @@ -177,6 +177,40 @@ def sample(population, k): """ return _pyrand().sample(population, k) +def random_error_position(n , number_errors): + r""" + Returns a list of exactly ``number_errors`` unique random numbers between 0 and ``n-1``. + This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + + INPUT: + + - ``number_errors`` -- the number of elements in the list + + - ``n`` -- upper bound for the elements of the list + + OUTPUT: + + - A list of integers + + EXAMPLES:: + + sage: random_error_position(6, 2) # random + [1, 4] + sage:set_random_seed(10) + sage: random_error_position(10,4) + [0, 2, 4, 9] + """ + error_position = [] + i = 0 + while i < n and number_errors > 0: + if random() < number_errors/(n-i): + error_position.append(i) + number_errors -= 1 + i += 1 + return error_position + + def random(): r""" Get the next random number in the range [0.0, 1.0). From d906934aab2190573228c26cf0aa94046d5e17a7 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 13 Apr 2015 17:05:31 +0200 Subject: [PATCH 437/665] #2072 remove the 3 remaining _invert_c_impl --- .../rings/padics/padic_ZZ_pX_CA_element.pxd | 1 - .../rings/padics/padic_ZZ_pX_CA_element.pyx | 23 +--------------- .../rings/padics/padic_ZZ_pX_CR_element.pxd | 1 - .../rings/padics/padic_ZZ_pX_CR_element.pyx | 21 --------------- .../rings/padics/padic_ZZ_pX_FM_element.pxd | 3 +-- .../rings/padics/padic_ZZ_pX_FM_element.pyx | 26 ------------------- 6 files changed, 2 insertions(+), 73 deletions(-) diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pxd b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pxd index e8acc72efae..cc02af0b23c 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pxd +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pxd @@ -18,7 +18,6 @@ cdef class pAdicZZpXCAElement(pAdicZZpXElement): cdef pAdicZZpXCAElement _new_c(self, long absprec) cdef pAdicZZpXCAElement _lshift_c(self, long n) cdef pAdicZZpXCAElement _rshift_c(self, long n) - cpdef RingElement _invert_c_impl(self) cpdef pAdicZZpXCAElement unit_part(self) cpdef _ntl_rep_abs(self) cpdef ntl_ZZ_pX _ntl_rep(self) diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index 42389f3da50..c200dd9b955 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -949,28 +949,7 @@ cdef class pAdicZZpXCAElement(pAdicZZpXElement): sage: ~z w^-5 + 4*w^-4 + 4*w^-3 + 4*w^-2 + 2*w^-1 + 1 + w + 4*w^2 + 4*w^3 + 4*w^4 + w^5 + w^6 + w^7 + 4*w^8 + 4*w^9 + 2*w^10 + w^11 + 2*w^12 + 4*w^13 + 4*w^14 + O(w^15) """ - return self.to_fraction_field()._invert_c_impl() - - cpdef RingElement _invert_c_impl(self): - """ - Returns the inverse of ``self``. - - EXAMPLES:: - - sage: R = ZpCA(5,5) - sage: S. = ZZ[] - sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 - sage: W. = R.ext(f) - sage: z = (1 + w)^5 - sage: y = ~z; y # indirect doctest - 1 + 4*w^5 + 4*w^6 + 3*w^7 + w^8 + 2*w^10 + w^11 + w^12 + 2*w^14 + 3*w^16 + 3*w^17 + 4*w^18 + 4*w^19 + 2*w^20 + 2*w^21 + 4*w^22 + 3*w^23 + 3*w^24 + O(w^25) - sage: y.parent() - Eisenstein Extension of 5-adic Field with capped relative precision 5 in w defined by (1 + O(5^5))*x^5 + (O(5^6))*x^4 + (3*5^2 + O(5^6))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + O(5^6))*x^2 + (5^3 + O(5^6))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + O(5^6)) - sage: z = z - 1 - sage: ~z - w^-5 + 4*w^-4 + 4*w^-3 + 4*w^-2 + 2*w^-1 + 1 + w + 4*w^2 + 4*w^3 + 4*w^4 + w^5 + w^6 + w^7 + 4*w^8 + 4*w^9 + 2*w^10 + w^11 + 2*w^12 + 4*w^13 + 4*w^14 + O(w^15) - """ - return self.to_fraction_field()._invert_c_impl() + return ~self.to_fraction_field() cpdef pAdicZZpXCRElement to_fraction_field(self): """ diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pxd b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pxd index 66883fa0253..693435ee035 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pxd +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pxd @@ -25,7 +25,6 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): cdef int _normalize(self) except -1 cdef pAdicZZpXCRElement _lshift_c(self, long n) cdef pAdicZZpXCRElement _rshift_c(self, long n) - cpdef RingElement _invert_c_impl(self) cpdef pAdicZZpXCRElement unit_part(self) cpdef ntl_ZZ_pX _ntl_rep_unnormalized(self) cpdef _ntl_rep_abs(self) diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index dbacb1dd2bb..87e45d9e516 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -1585,27 +1585,6 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): """ Returns the inverse of ``self``. - EXAMPLES:: - - sage: R = Zp(5,5) - sage: S. = R[] - sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 - sage: W. = R.ext(f) - sage: z = (1 + w)^5 - sage: y = ~z; y # indirect doctest - 1 + 4*w^5 + 4*w^6 + 3*w^7 + w^8 + 2*w^10 + w^11 + w^12 + 2*w^14 + 3*w^16 + 3*w^17 + 4*w^18 + 4*w^19 + 2*w^20 + 2*w^21 + 4*w^22 + 3*w^23 + 3*w^24 + O(w^25) - sage: y.parent() - Eisenstein Extension of 5-adic Field with capped relative precision 5 in w defined by (1 + O(5^5))*x^5 + (O(5^6))*x^4 + (3*5^2 + O(5^6))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + O(5^6))*x^2 + (5^3 + O(5^6))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + O(5^6)) - sage: z = z - 1 - sage: ~z - w^-5 + 4*w^-4 + 4*w^-3 + 4*w^-2 + 2*w^-1 + 1 + w + 4*w^2 + 4*w^3 + 4*w^4 + w^5 + w^6 + w^7 + 4*w^8 + 4*w^9 + 2*w^10 + w^11 + 2*w^12 + 4*w^13 + 4*w^14 + O(w^15) - """ - return self._invert_c_impl() - - cpdef RingElement _invert_c_impl(self): - """ - Returns the inverse of ``self``. - EXAMPLES:: sage: R = Zp(5,5) diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pxd b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pxd index f097ee9e25e..807978615c2 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pxd +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pxd @@ -8,6 +8,5 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): cdef pAdicZZpXFMElement _new_c(self) cdef pAdicZZpXFMElement _lshift_c(self, long n) cdef pAdicZZpXFMElement _rshift_c(self, long n) - cpdef RingElement _invert_c_impl(self) - cpdef pAdicZZpXFMElement unit_part(self) \ No newline at end of file + cpdef pAdicZZpXFMElement unit_part(self) diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index d910ba73d41..c365be33d9c 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -506,32 +506,6 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): If ``self`` is not a unit, raises a ``ValueError``. - EXAMPLES:: - - sage: R = ZpFM(5,5) - sage: S. = R[] - sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 - sage: W. = R.ext(f) - sage: z = (1 + w)^5 - sage: y = ~z; y # indirect doctest - 1 + 4*w^5 + 4*w^6 + 3*w^7 + w^8 + 2*w^10 + w^11 + w^12 + 2*w^14 + 3*w^16 + 3*w^17 + 4*w^18 + 4*w^19 + 2*w^20 + 2*w^21 + 4*w^22 + 3*w^23 + 3*w^24 + O(w^25) - sage: y.parent() - Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (O(5^5))*x^4 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) - sage: z = z - 1 - sage: ~z - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit - """ - return self._invert_c_impl() - - cpdef RingElement _invert_c_impl(self): - """ - Returns the inverse of ``self``, as long as ``self`` is a - unit. - - If ``self`` is not a unit, raises a ``ValueError``. - EXAMPLES:: sage: R = ZpFM(5,5) From 3d1bb2e121675d0a4fae0d2d011ccdaedbd5a7c3 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 22 Apr 2015 13:32:02 +0200 Subject: [PATCH 438/665] Allow exceptions in Polynomial_generic_dense.__normalize() --- .../rings/polynomial/polynomial_element.pxd | 6 +---- .../rings/polynomial/polynomial_element.pyx | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pxd b/src/sage/rings/polynomial/polynomial_element.pxd index 230b783d2a2..fcd4a658d13 100644 --- a/src/sage/rings/polynomial/polynomial_element.pxd +++ b/src/sage/rings/polynomial/polynomial_element.pxd @@ -20,10 +20,6 @@ cdef class Polynomial(CommutativeAlgebraElement): cdef class Polynomial_generic_dense(Polynomial): cdef Polynomial_generic_dense _new_c(self, list coeffs, Parent P) cdef list __coeffs - cdef void __normalize(self) -# cdef _dict_to_list(self, x, zero) + cdef int __normalize(self) except -1 cpdef is_Polynomial(f) - -#cdef class Polynomial_generic_sparse(Polynomial): -# cdef object __coeffs # a python dict (for now) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2e3c846c0af..b4594a4e008 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7353,7 +7353,8 @@ cdef class Polynomial_generic_dense(Polynomial): sage: loads(dumps(f)) == f True - Make sure we're testing the right method. + Make sure we're testing the right method:: + sage: type(f) """ @@ -7362,8 +7363,24 @@ cdef class Polynomial_generic_dense(Polynomial): def __nonzero__(self): return len(self.__coeffs) > 0 - cdef void __normalize(self): - x = self.__coeffs + cdef int __normalize(self) except -1: + """ + TESTS: + + Check that exceptions are propagated correctly (:trac:`18274`):: + + sage: class BrokenRational(Rational): + ....: def __nonzero__(self): + ....: raise NotImplementedError("cannot check whether number is non-zero") + sage: z = BrokenRational() + sage: R. = QQ[] + sage: from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense + sage: Polynomial_generic_dense(R, [z]) + Traceback (most recent call last): + ... + NotImplementedError: cannot check whether number is non-zero + """ + cdef list x = self.__coeffs cdef Py_ssize_t n = len(x) - 1 while n >= 0 and not x[n]: del x[n] From 9fd73dc4afc8590f48907e548cfa4bd96f5bd1b6 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 22 Apr 2015 14:36:25 +0200 Subject: [PATCH 439/665] #17932 cosmetic changes to module docstrings --- src/sage/databases/sql_db.py | 2 +- src/sage/ext/fast_callable.pyx | 2 +- src/sage/ext/fast_eval.pyx | 2 +- src/sage/media/wav.py | 4 ++-- src/sage/misc/c3_controlled.pyx | 2 +- src/sage/misc/lazy_string.py | 2 +- src/sage/misc/object_multiplexer.py | 2 +- src/sage/misc/proof.py | 2 +- src/sage/structure/debug_options.pyx | 2 +- src/sage/structure/generators.pyx | 2 +- src/sage/structure/test_factory.py | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index f862d9a4e9b..e9acd6eb91b 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -1,5 +1,5 @@ """ -Relational (sqlite) Databases Module. +Relational (sqlite) Databases Module INFO: diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index d6e2410a15d..e3f8e408608 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -1,5 +1,5 @@ r""" -Fast Expression Evaluation. +Fast Expression Evaluation For many applications such as numerical integration, differential equation approximation, plotting a 3d surface, optimization problems, diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index 2aea7f98538..f3ae964d74c 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -1,5 +1,5 @@ r""" -Fast Numerical Evaluation. +Fast Numerical Evaluation For many applications such as numerical integration, differential equation approximation, plotting a 3d surface, optimization problems, diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index 89e437dcb94..775326af301 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -1,5 +1,5 @@ r""" -Work with WAV files. +Work with WAV files A WAV file is a header specifying format information, followed by a sequence of bytes, representing the state of some audio signal over a @@ -12,7 +12,7 @@ number of bytes per sample. Typically this is either 1 or 2 bytes. The wav module supplies more convenient access to this data. In -particular, see the docstring for \code{Wave.channel_data()}. +particular, see the docstring for ``Wave.channel_data()``. The header contains information necessary for playing the WAV file, including the number of frames per second, the number of bytes per diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index fcee4db6726..cb1c4fe2e18 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -1,5 +1,5 @@ """ -The ``C3`` algorithm, under control of a total order. +The C3 algorithm, under control of a total order Abstract ======== diff --git a/src/sage/misc/lazy_string.py b/src/sage/misc/lazy_string.py index a1e6c5aabce..7c5148ae483 100644 --- a/src/sage/misc/lazy_string.py +++ b/src/sage/misc/lazy_string.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Lazy strings. +Lazy strings Based on speaklater: https://github.com/mitsuhiko/speaklater. diff --git a/src/sage/misc/object_multiplexer.py b/src/sage/misc/object_multiplexer.py index 90e6eace75d..3c1ed5463d8 100644 --- a/src/sage/misc/object_multiplexer.py +++ b/src/sage/misc/object_multiplexer.py @@ -1,5 +1,5 @@ """ -Multiplex calls to one object to calls to many objects. +Multiplex calls to one object to calls to many objects AUTHORS: diff --git a/src/sage/misc/proof.py b/src/sage/misc/proof.py index 4d44d89857f..12a14869fd5 100644 --- a/src/sage/misc/proof.py +++ b/src/sage/misc/proof.py @@ -1,5 +1,5 @@ """ -Whether or not computations are provably correct by default. +Whether or not computations are provably correct by default """ #proof = False diff --git a/src/sage/structure/debug_options.pyx b/src/sage/structure/debug_options.pyx index eb794211203..14a1a2dfd13 100644 --- a/src/sage/structure/debug_options.pyx +++ b/src/sage/structure/debug_options.pyx @@ -1,5 +1,5 @@ """ -Debug options for the `sage.structure` modules +Debug options for the :mod:`sage.structure` modules EXAMPLES:: diff --git a/src/sage/structure/generators.pyx b/src/sage/structure/generators.pyx index b9ecd1f90d4..1daf9b5e6c2 100644 --- a/src/sage/structure/generators.pyx +++ b/src/sage/structure/generators.pyx @@ -1,5 +1,5 @@ """ -(Algebraic) generators of a Sage object. +(Algebraic) generators of a Sage object """ from sage.structure.sage_object cimport SageObject diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index c3b0a7f9550..722b957b515 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -1,5 +1,5 @@ """ -Test of the :mod:`~sage.structure.factory` module. +Test of the :mod:`~sage.structure.factory` module """ #***************************************************************************** From 8cd8bbabfcb478512864a551efd4157c2ac43d7e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 22 Apr 2015 14:37:08 +0200 Subject: [PATCH 440/665] Trac 18275: fix __sub__ for additive magmas --- src/sage/categories/additive_magmas.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index d51eaea7924..47f692b1021 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -827,12 +827,33 @@ def __sub__(left, right): sage: a - b B['a'] - B['b'] """ - if have_same_parent(left, right) and hasattr(left, "_sub_"): + if have_same_parent(left, right): return left._sub_(right) from sage.structure.element import get_coercion_model import operator return get_coercion_model().bin_op(left, right, operator.sub) + def _sub_(left, right): + r""" + Default implementation of difference. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b']) + sage: a,b = F.basis() + sage: a - b + B['a'] - B['b'] + + TESTS: + + Check that :trac:`18275` is fixed:: + + sage: C = GF(5).cartesian_product(GF(5)) + sage: C.one() - C.one() + (0, 0) + """ + return left._add_(-right) + def __neg__(self): """ Return the negation of ``self``, if it exists. From f910ad888bb07e504d95859327ee25a6cd33085c Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 22 Apr 2015 14:43:47 +0200 Subject: [PATCH 441/665] #17932 misc/flatten.py: fix indentation --- src/sage/misc/flatten.py | 92 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/sage/misc/flatten.py b/src/sage/misc/flatten.py index cfae90fd3ac..17f0cb8abe7 100644 --- a/src/sage/misc/flatten.py +++ b/src/sage/misc/flatten.py @@ -2,20 +2,20 @@ import sys def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): - """ - Flattens a nested list. + """ + Flattens a nested list. - INPUT: + INPUT: - - in_list -- a list or tuple - - ltypes -- optional list of particular types to flatten - - max_level -- the maximum level to flatten + - in_list -- a list or tuple + - ltypes -- optional list of particular types to flatten + - max_level -- the maximum level to flatten - OUTPUT: + OUTPUT: a flat list of the entries of in_list - EXAMPLES:: + EXAMPLES:: sage: flatten([[1,1],[1],2]) [1, 1, 1, 2] @@ -31,18 +31,18 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): [3] - In the following example, the vector isn't flattened because - it is not given in the ltypes input. :: + In the following example, the vector isn't flattened because + it is not given in the ltypes input. :: sage: flatten((['Hi',2,vector(QQ,[1,2,3])],(4,5,6))) ['Hi', 2, (1, 2, 3), 4, 5, 6] - We give the vector type and then even the vector gets flattened:: + We give the vector type and then even the vector gets flattened:: sage: flatten((['Hi',2,vector(QQ,[1,2,3])], (4,5,6)), ltypes=(list, tuple,sage.modules.vector_rational_dense.Vector_rational_dense)) ['Hi', 2, 1, 2, 3, 4, 5, 6] - We flatten a finite field. :: + We flatten a finite field. :: sage: flatten(GF(5)) [0, 1, 2, 3, 4] @@ -51,37 +51,37 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): sage: flatten([GF(5)], ltypes = (list, tuple, sage.rings.finite_rings.finite_field_prime_modn.FiniteField_prime_modn)) [0, 1, 2, 3, 4] - Degenerate cases:: - - sage: flatten([[],[]]) - [] - sage: flatten([[[]]]) - [] - """ - index = 0 - current_level = 0 - new_list = [x for x in in_list] - level_list = [0]*len(in_list) - - while index < len(new_list): - len_v=None - while isinstance(new_list[index], ltypes) and current_level Date: Wed, 22 Apr 2015 14:46:04 +0200 Subject: [PATCH 442/665] #17932 remove media.channels from the manual --- src/doc/en/reference/misc/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index 3ddf72b3494..66b34cc0b9f 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -81,8 +81,9 @@ Media :maxdepth: 1 sage/structure/graphics_file - sage/media/channels sage/media/wav +.. underscore-methods only +.. sage/media/channels Warnings ~~~~~~~~ From 5ee95d78300d7a2388892c6d647c52b4ce5bd285 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 22 Apr 2015 15:13:22 +0200 Subject: [PATCH 443/665] Changed code of random_error_vector --- src/sage/coding/all.py | 1 - src/sage/coding/channel_constructions.py | 29 ++++++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 9627cd1c796..84e1b6e81f5 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -77,4 +77,3 @@ lazy_import('sage.coding', 'channels_catalog', 'channels') import sage.coding.channel_constructions - diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index c6d851df7b5..066b205d5d6 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -31,7 +31,7 @@ from sage.combinat.cartesian_product import CartesianProduct from sage.modules.free_module import VectorSpace -def _random_error_vector(n, F, error_positions): +def random_error_vector(n, F, error_positions): r""" Return a vector of length ``n`` over ``F`` filled with random non-zero coefficients at the positions given by ``error_positions``. @@ -39,7 +39,7 @@ def _random_error_vector(n, F, error_positions): This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) and was written by Johan Nielsen. - ..NOTE:: + .. NOTE:: This is a helper function, which should only be used when implementing new channels. @@ -57,21 +57,20 @@ def _random_error_vector(n, F, error_positions): EXAMPLES:: - sage: sage.coding.channel_constructions._random_error_vector(5, GF(2), [1,3]) + sage: sage.coding.channel_constructions.random_error_vector(5, GF(2), [1,3]) (0, 1, 0, 1, 0) """ vect = [F.zero()]*n for i in error_positions: - while vect[i].is_zero(): - vect[i] = F.random_element() + vect[i] = F._random_nonzero_element() return vector(F, vect) -def _tuple_to_integer(value): +def tuple_to_integer(value): r""" Returns an integer from ``value``. If ``value`` is a tuple, it will return a random integer between its bounds. - ..NOTE:: + .. NOTE:: This is a helper function, which should only be used when implementing new channels. @@ -85,10 +84,10 @@ def _tuple_to_integer(value): EXAMPLES:: - sage: sage.coding.channel_constructions._tuple_to_integer(4) + sage: sage.coding.channel_constructions.tuple_to_integer(4) 4 - sage: sage.coding.channel_constructions._tuple_to_integer((1,5)) # random + sage: sage.coding.channel_constructions.tuple_to_integer((1,5)) # random 3 """ value = value if not hasattr(value, "__iter__") else randint(value[0], value[1]) @@ -384,10 +383,10 @@ def transmit_unsafe(self, message): sage: Chan.transmit_unsafe(msg) # random (4, 14, 15, 16, 17, 42) """ - number_errors = _tuple_to_integer(self.number_errors()) + number_errors = tuple_to_integer(self.number_errors()) V = self.input_space() n = V.dimension() - error_vector = _random_error_vector(n, V.base_ring(),\ + error_vector = random_error_vector(n, V.base_ring(),\ random_error_position(n, number_errors)) return message + error_vector @@ -579,8 +578,8 @@ def transmit_unsafe(self, message): sage: Chan.transmit_unsafe(msg) # random ((0, 14, 15, 0, 26, 53, 45, 9, 7, 14, 3), (1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) """ - number_errors = _tuple_to_integer(self.number_errors()) - number_erasures = _tuple_to_integer(self.number_erasures()) + number_errors = tuple_to_integer(self.number_errors()) + number_erasures = tuple_to_integer(self.number_erasures()) V = self.input_space() n = V.dimension() @@ -593,8 +592,8 @@ def transmit_unsafe(self, message): erasure_positions = [ erroneous_positions[i] for i in\ range(number_errors + number_erasures) if i not in error_split] - error_vector = _random_error_vector(n, V.base_ring(), error_positions) - erasure_vector = _random_error_vector(n , GF(2), erasure_positions) + error_vector = random_error_vector(n, V.base_ring(), error_positions) + erasure_vector = random_error_vector(n , GF(2), erasure_positions) message = message + error_vector From 47b6a0e84a2faa4eb7cf934b79eadc3a2ad9e6cf Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 25 Aug 2013 11:23:02 +0200 Subject: [PATCH 444/665] #14982 Clean up after querying the coercion system with a temporary element_class in NumberField_cyclotomic * 92505a4f1a50ba57fd44200808aab0e89af82672 makes NumberField_cyclotomic perform some nontrivial computations before setting its element_class. With the change to the coercion system proposed as part of #14982, these computations would result in an_element() being called and a value with the wrong element class being cached. This patch keeps the hack from 92505a4f1a50ba57fd44200808aab0e89af82672 but adds some cleanup afterwards to work around the issue. This entails renaming Parent.__an_element to Parent._cache_an_element to make it accessible to subclasses. (It would be better to clear _all_ caches associated to the object, but I don't know how to do that.) * Also simplify NFE_quadratic.__init__ as suggested by Vincent Delecroix --- src/sage/rings/number_field/number_field.py | 6 ++++++ .../number_field_element_quadratic.pyx | 19 +++---------------- src/sage/structure/parent.pxd | 2 +- src/sage/structure/parent.pyx | 8 +++++--- src/sage/structure/parent_old.pyx | 10 +++++----- 5 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 27caabb0f72..25e7bcda7b8 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8447,6 +8447,8 @@ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_a sage: type(CyclotomicField(6).one()) + sage: type(CyclotomicField(6).an_element()) + sage: type(CyclotomicField(15).zero()) """ @@ -8474,7 +8476,11 @@ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_a # imaginary value). # Note that the test is done with NumberFieldElement and not with # NumberFieldElement_quadratic which requires somehow this flag. + # As a consequence, a result of _an_element_() with the wrong class + # is cached during the call to has_coerce_map_from. We reset the + # cache afterwards. self._standard_embedding = not CDF.has_coerce_map_from(self) or CDF(self.gen()).imag() > 0 + self._cache_an_element = None self._element_class = number_field_element_quadratic.NumberFieldElement_quadratic if n == 4: diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 32e1acc684f..cff058e086f 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -209,22 +209,9 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_set_ui(self.denom, 1) self._reduce_c_() - # set the attribute standard embedding which is used in the method - # __cmp__ - try: - self.standard_embedding = parent._standard_embedding - except AttributeError: - emb = parent.coerce_embedding() - if emb is None: - self.standard_embedding = True - try: - parent._standard_embedding = True - except AttributeError: - pass - else: - raise ValueError("A parent of NumberFieldElement_quadratic with " - "a canonical embedding should have an attribute " - "_standard_embedding (used for comparisons of elements)") + # set the attribute standard embedding which is used in the methods + # __cmp__, sign, real, imag, floor, ceil, ... + self.standard_embedding = parent._standard_embedding cdef _new(self): """ diff --git a/src/sage/structure/parent.pxd b/src/sage/structure/parent.pxd index 5104d448d03..836f4139a97 100644 --- a/src/sage/structure/parent.pxd +++ b/src/sage/structure/parent.pxd @@ -55,7 +55,7 @@ cdef class Parent(category_object.CategoryObject): cpdef coerce(self, x) cpdef an_element(self) - cdef public object __an_element + cdef public object _cache_an_element # For internal use diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 48a40986e7b..6df799f6af0 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2839,9 +2839,11 @@ cdef class Parent(category_object.CategoryObject): ... EmptySetError """ - if self.__an_element is None: - self.__an_element = self._an_element_() - return self.__an_element + # _cache_an_element, not _cache__an_element, to prevent a possible + # conflict with @cached_method + if self._cache_an_element is None: + self._cache_an_element = self._an_element_() + return self._cache_an_element def _an_element_(self): """ diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index 4b977ed1142..25bc2905b8f 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -405,13 +405,13 @@ cdef class Parent(parent.Parent): cpdef _an_element_c(self): # do not override this (call from Cython) check_old_coerce(self) - if not self.__an_element is None: - return self.__an_element + if not self._cache_an_element is None: + return self._cache_an_element if HAS_DICTIONARY(self): - self.__an_element = self._an_element_impl() + self._cache_an_element = self._an_element_impl() else: - self.__an_element = self._an_element_c_impl() - return self.__an_element + self._cache_an_element = self._an_element_c_impl() + return self._cache_an_element # This should eventually be inherited from the EnumeratedSets() category # This is just a convenient spot to cover the relevant cython parents, From 61c73bb1e313f39737c24d8ffa34aaa0d5634f49 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 26 Aug 2013 08:49:08 +0200 Subject: [PATCH 445/665] #14982 Make coercions that go through lazy fields more robust Coercions into lazy fields are currently defined by a kind of universal property: anything that coerces into parents into which the lazy field coerces also coerces into the lazy field. Besides, one of the possible classes of lazy field elements is a wrapper around elements of other exact fields, and the coercion of such wrappers into other parents simply converts the wrapped elements. This is a bit fragile, both because there is no way to know for sure all the parents into which the lazy field coerces, and because that way to define and apply coercion maps may lead to infinite loops. This patch makes three changes to mitigate the issue. 1. Test for coercions into all (known) rings into which the lazy field coerces instead of just into the associated interval field. 2. Only consider direct (as opposed to composite) coercions. 3. Check that the conversion path does not already goes through the lazy field when converting a wrapper. --- src/sage/categories/map.pyx | 25 ++++++++++++++++++++++ src/sage/rings/real_lazy.pyx | 41 +++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index fc54b041bd0..e420629f6bc 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -591,6 +591,17 @@ cdef class Map(Element): s += "\n Defn: %s"%('\n '.join(d.split('\n'))) return s + def domains(self): + """ + Yield the domain of self. In general, iterate over the domains of + the factors of a composite map. + + EXAMPLES:: + sage: list(QQ.coerce_map_from(ZZ).domains()) + [Integer Ring] + """ + yield self.domain() + def category_for(self): """ Returns the category self is a morphism for. @@ -1903,3 +1914,17 @@ cdef class FormalCompositeMap(Map): if all(f.is_surjective() for f in without_bij): return True raise NotImplementedError("Not enough information to deduce surjectivity.") + + def domains(self): + """ + Iterate over the domains of the factors of self. + + EXAMPLES::: + + sage: f = QQ.coerce_map_from(ZZ) + sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) + sage: list((g*f).domains()) + [Integer Ring, Rational Field] + """ + for f in self.__list: + yield f.domain() diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 0d77212d83a..7686a122a33 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -26,7 +26,9 @@ from operator import add, sub, mul, div, pow, neg, inv cdef canonical_coercion from sage.structure.element import canonical_coercion +from sage.structure.all import parent +import sage.categories.map from sage.categories.morphism cimport Morphism from sage.rings.ring cimport Field import sage.rings.infinity @@ -112,8 +114,20 @@ cdef class LazyField(Field): cpdef _coerce_map_from_(self, R): r""" The only things that coerce into this ring are exact rings that - embed into `\RR` or `\CC` (depending on whether or not this field - is real or complex). + embed into `\RR` or `\CC` (depending on whether this field + is real or complex), that is, exact rings that coerce into all + rings into which this ring coerces. + + .. NOTE:: + + The rings into which this ring coerces are currently the + corresponding floating-point fields (RealField(p) or + ComplexField(p)), machine-precision floating-point fields (RDF, + CDF), and interval fields (RealIntervalField(p), + ComplexIntervalField(p)). This method should be updated if a new + parent is added that declares a coercion from RLF/CLF but not from + one of these, otherwise coercions of elements of type LazyWrapper + into the new ring might fail. EXAMPLES:: @@ -141,8 +155,18 @@ cdef class LazyField(Field): if R in [int, long]: from sage.structure.parent import Set_PythonType return LazyWrapperMorphism(Set_PythonType(R), self) - elif self.interval_field().has_coerce_map_from(R) and R.is_exact(): - return LazyWrapperMorphism(R, self) + elif R.is_exact(): + ivf = self.interval_field() + mor = ivf.coerce_map_from(R) + # Indirect coercions might lead to loops both in the coercion + # discovery algorithm and when trying to convert LazyWrappers, + # so we only consider direct coercions. + if mor is not None and not isinstance(mor, sage.categories.map.FormalCompositeMap): + mor = ivf._middle_field().coerce_map_from(R) + if mor is not None and not isinstance(mor, sage.categories.map.FormalCompositeMap): + return LazyWrapperMorphism(R, self) + # We can skip the test for a coercion to RDF/CDF since RR/CC + # already coerce into it. def algebraic_closure(self): """ @@ -1004,7 +1028,14 @@ cdef class LazyWrapper(LazyFieldElement): sage: a.eval(ZZ).parent() Integer Ring """ - return R(self._value) + try: + mor = R.convert_map_from(parent(self._value)) + except AttributeError: + return R(self._value) + if mor is not None and self.parent() not in mor.domains(): + return mor(self._value) + else: + raise TypeError("unable to convert {} to an element of {}".format(self._value, R)) def __reduce__(self): """ From 0aa11af6392cc649b9030bb53843152ebc96b25e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 14 Apr 2015 17:40:21 +0200 Subject: [PATCH 446/665] #14982 fix q_binomial --- src/sage/combinat/q_analogues.py | 77 +++++++++++++----------- src/sage/rings/polynomial/cyclotomic.pyx | 26 +++++--- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index 226ee138a43..e4c21a06386 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -18,6 +18,7 @@ from sage.misc.cachefunc import cached_function from sage.misc.all import prod +from sage.structure.element import parent from sage.rings.all import ZZ from sage.combinat.dyck_word import DyckWords from sage.combinat.partition import Partition @@ -215,7 +216,7 @@ def q_binomial(n, k, q=None, algorithm='auto'): sage: q_binomial(1/2,1) Traceback (most recent call last): ... - ValueError: arguments (1/2, 1) must be integers + TypeError: no conversion of this rational to integer One checks that `n` is nonnegative:: @@ -232,8 +233,13 @@ def q_binomial(n, k, q=None, algorithm='auto'): This also works for complex roots of unity:: - sage: q_binomial(6,1,I) - 1 + I + sage: q_binomial(6, 1, QQbar(I)) + I + 1 + + Note that the symbolic computation works (see :trac:`14982`):: + + sage: q_binomial(6, 1, I) + I + 1 Check that the algorithm does not matter:: @@ -256,14 +262,10 @@ def q_binomial(n, k, q=None, algorithm='auto'): - Frederic Chapoton, David Joyner and William Stein """ # sanity checks - if not( n in ZZ and k in ZZ ): - raise ValueError("arguments (%s, %s) must be integers" % (n, k)) + n = ZZ(n) + k = ZZ(k) if n < 0: raise ValueError('n must be nonnegative') - if not(0 <= k and k <= n): - return 0 - - k = min(n-k,k) # Pick the smallest k # polynomiality test if q is None: @@ -273,10 +275,19 @@ def q_binomial(n, k, q=None, algorithm='auto'): else: from sage.rings.polynomial.polynomial_element import Polynomial is_polynomial = isinstance(q, Polynomial) - from sage.symbolic.ring import SR + + R = parent(q) + zero = R(0) + one = R(1) + + if not(0 <= k and k <= n): + return zero + + k = min(n-k,k) # Pick the smallest k # heuristic choice of the fastest algorithm if algorithm == 'auto': + from sage.symbolic.ring import SR if is_polynomial: if n <= 70 or k <= n/4: algorithm = 'naive' @@ -295,31 +306,29 @@ def q_binomial(n, k, q=None, algorithm='auto'): raise ValueError("invalid algorithm choice") # the algorithms - try: - if algorithm == 'naive': - denomin = prod([1 - q**i for i in range(1, k+1)]) - if denomin == 0: # q is a root of unity, use the cyclotomic algorithm - algorithm = 'cyclo_generic' - else: - numerat = prod([1 - q**i for i in range(n-k+1, n+1)]) + if algorithm == 'naive': + denom = prod(one - q**i for i in range(1, k+1)) + if not denom: # q is a root of unity, use the cyclotomic algorithm + return cyclotomic_value(n, k, q, algorithm='cyclotomic') + else: + num = prod(one - q**i for i in range(n-k+1, n+1)) + try: + return num//denom + except TypeError: try: - return numerat//denomin - except TypeError: - return numerat/denomin - from sage.functions.all import floor - if algorithm == 'cyclo_generic': - from sage.rings.polynomial.cyclotomic import cyclotomic_value - return prod(cyclotomic_value(d,q) - for d in range(2,n+1) - if floor(n/d) != floor(k/d) + floor((n-k)/d)) - if algorithm == 'cyclo_polynomial': - R = q.parent() - return prod(R.cyclotomic_polynomial(d) - for d in range(2,n+1) - if floor(n/d) != floor(k/d) + floor((n-k)/d)) - except (ZeroDivisionError, TypeError): - # As a last attempt, do the computation formally and then substitute - return q_binomial(n, k)(q) + return num/denom + except (TypeError,ZeroDivisionError): + #try a substitution + return q_binomial(n,k)(q) + elif algorithm == 'cyclo_generic': + from sage.rings.polynomial.cyclotomic import cyclotomic_value + return prod(cyclotomic_value(d,q) + for d in range(2,n+1) + if (n/d).floor() != (k/d).floor() + ((n-k)/d).floor()) + elif algorithm == 'cyclo_polynomial': + return prod(R.cyclotomic_polynomial(d) + for d in range(2,n+1) + if (n/d).floor() != (k/d).floor() + ((n-k)/d).floor()) def gaussian_binomial(n, k, q=None, algorithm='auto'): r""" diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index 13896823990..9bea126a794 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -30,8 +30,11 @@ include "sage/ext/stdsage.pxi" include "sage/ext/interrupt.pxi" include "sage/ext/cdefs.pxi" +from sage.structure.element cimport parent_c + from sage.rings.arith import factor from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ from sage.misc.all import prod, subsets from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational @@ -276,19 +279,29 @@ def cyclotomic_value(n, x): -t^7 - t^6 - t^5 + t^2 + t + 1 sage: cyclotomic_value(10,mod(3,4)) 1 + + Check that the issue with symbolic element in :trac:`14982` is fixed:: + + sage: a = cyclotomic_value(3, I) + sage: a.pyobject() + I + sage: parent(_) + Number Field in I with defining polynomial x^2 + 1 """ - n = int(n) + n = ZZ(n) if n < 3: if n == 1: - return x - 1 + return x - ZZ.one() if n == 2: - return x + 1 + return x + ZZ.one() raise ValueError("n must be positive") + P = parent_c(x) try: - return x.parent()(pari.polcyclo_eval(n, x)) + return P(pari.polcyclo_eval(n, x).sage()) except Exception: pass + one = P(1) # The following is modeled on the implementation in PARI and is # used for cases for which PARI doesn't work. These are in @@ -297,11 +310,11 @@ def cyclotomic_value(n, x): # - x is some Sage type which cannot be converted to PARI; # - PARI's algorithm encounters a zero-divisor which is not zero. - factors = factor(n) + factors = n.factor() cdef Py_ssize_t i, j, ti, L, root_of_unity = -1 primes = [p for p, e in factors] L = len(primes) - if any([e != 1 for p, e in factors]): + if any(e != 1 for p, e in factors): # If there are primes that occur in the factorization with multiplicity # greater than one we use the fact that Phi_ar(x) = Phi_r(x^a) when all # primes dividing a divide r. @@ -318,7 +331,6 @@ def cyclotomic_value(n, x): xd = [x] # the x^d for d | n cdef char mu cdef char* md = sage_malloc(sizeof(char) * (1 << L)) # the mu(d) for d | n - one = x.parent()(1) try: md[0] = 1 if L & 1: From a3227dd071f7efc9822a66beb977607aee2f5ac5 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 14 Apr 2015 18:30:20 +0200 Subject: [PATCH 447/665] #14982 Robustify PolynomialRing_general._coerce_map_from_() So that it survives a doctest from pushout.pushout that abuses the polynomial ring classes by creating a derived class whose instances are not really polynomial rings (and, in particular, have a different construction functor). --- src/sage/rings/polynomial/polynomial_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index f367ed9ac74..70d47d7e7a6 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -639,7 +639,7 @@ def _coerce_map_from_(self, P): if is_PolynomialRing(P): if self.__is_sparse and not P.is_sparse(): return False - if P.variable_name() == self.variable_name(): + if P.construction()[0] == self.construction()[0]: if P.base_ring() is base_ring and \ base_ring is ZZ_sage: # We're trying to coerce from FLINT->NTL From d99564520a5fd599c0fea62b86d0bdbfbd35c1a4 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 26 Aug 2013 08:49:18 +0200 Subject: [PATCH 448/665] #14982 Consider coercions of parents with embeddings that do not use the embedding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a parent R declared a coerce_embedding into S, Sage's coercion system used to _only_ consider coercions R → T of the form R → S → T, with unfortunate consequences for, say, T = R[x]. This patch makes the coercion system try some other coercion paths before using the embedding (unless T is S). --- src/sage/structure/parent.pyx | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 6df799f6af0..bad7412c172 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2417,7 +2417,7 @@ cdef class Parent(category_object.CategoryObject): """ Precedence for discovering a coercion S -> self goes as follows: - 1. If S has an embedding into T, look for T -> self and return composition + 1. If S has an embedding into self, return that embedding. 2. If self._coerce_map_from_(S) is NOT exactly one of @@ -2425,11 +2425,14 @@ cdef class Parent(category_object.CategoryObject): - DefaultConvertMap_unique - NamedConvertMap - return this map + return this map. 3. Traverse the coercion lists looking for another map returning the map from step (2) if none is found. + 4. If S has an embedding into some parent T, look for T -> self and + return composition. + In the future, multiple paths may be discovered and compared. TESTS: @@ -2482,14 +2485,41 @@ cdef class Parent(category_object.CategoryObject): sage: X = P() sage: X.has_coerce_map_from(ZZ) True + + Check that :trac:`14982` is fixed, and more generally that we discover + sensible coercion paths in the presence of embeddings:: + + sage: K. = NumberField(x^2+1/2, embedding=CC(0,1)) + sage: L = NumberField(x^2+2, 'b', embedding=1/a) + sage: PolynomialRing(L, 'x').coerce_map_from(L) + Polynomial base injection morphism: + From: Number Field in b with defining polynomial x^2 + 2 + To: Univariate Polynomial Ring in x over Number Field in b with defining polynomial x^2 + 2 + sage: PolynomialRing(K, 'x').coerce_map_from(L) + Composite map: + From: Number Field in b with defining polynomial x^2 + 2 + To: Univariate Polynomial Ring in x over Number Field in a with defining polynomial x^2 + 1/2 + Defn: Generic morphism: + From: Number Field in b with defining polynomial x^2 + 2 + To: Number Field in a with defining polynomial x^2 + 1/2 + Defn: b -> -2*a + then + Polynomial base injection morphism: + From: Number Field in a with defining polynomial x^2 + 1/2 + To: Univariate Polynomial Ring in x over Number Field in a with defining polynomial x^2 + 1/2 + sage: MatrixSpace(L, 2, 2).coerce_map_from(L) + Call morphism: + From: Number Field in b with defining polynomial x^2 + 2 + To: Full MatrixSpace of 2 by 2 dense matrices over Number Field in b with defining polynomial x^2 + 2 + sage: PowerSeriesRing(L, 'x').coerce_map_from(L) + Conversion map: + From: Number Field in b with defining polynomial x^2 + 2 + To: Power Series Ring in x over Number Field in b with defining polynomial x^2 + 2 """ best_mor = None if isinstance(S, Parent) and (S)._embedding is not None: if (S)._embedding.codomain() is self: return (S)._embedding - connecting = self._internal_coerce_map_from((S)._embedding.codomain()) - if connecting is not None: - return (S)._embedding.post_compose(connecting) cdef map.Map mor user_provided_mor = self._coerce_map_from_(S) @@ -2551,7 +2581,13 @@ cdef class Parent(category_object.CategoryObject): if mor_found >= num_paths: return best_mor - return best_mor + if best_mor is not None: + return best_mor + + if isinstance(S, Parent) and (S)._embedding is not None: + connecting = self._internal_coerce_map_from((S)._embedding.codomain()) + if connecting is not None: + return (S)._embedding.post_compose(connecting) cpdef convert_map_from(self, S): """ From 19dfb413ce82458835b3e7e23cee66b0f1ce2255 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 22 Apr 2015 06:28:41 -0700 Subject: [PATCH 449/665] WeylCharacterRing optional in self.branch --- .../root_system/integrable_representations.py | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 0c0f7fd394c..cb6b9556cbf 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -21,7 +21,7 @@ from sage.matrix.constructor import Matrix from sage.functions.other import floor from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet -import sage.combinat.root_system.weyl_characters +from sage.combinat.root_system.weyl_characters import WeylCharacterRing # TODO: Make this a proper parent and implement actions class IntegrableRepresentation(CategoryObject, UniqueRepresentation): @@ -778,7 +778,7 @@ def modular_characteristic(self, mu=None): mu = self.to_weight(n) return m_Lambda-self._inner_pp(mu,mu)/(2*k) - def branch(self, wcring, depth): + def branch(self, weyl_character_ring=None, depth=5): """ If ``self`` is a representation of the untwisted affine Lie algebra of Cartan type ``[X, r, 1]``, then corresponding to the inclusion of ``[X, r]`` in @@ -786,17 +786,19 @@ def branch(self, wcring, depth): of type ``[X, r]``. The `k`-th representation of this sequence is the restriction of all weights in which `\delta` has coefficient `k`. - INPUT: + OPTIONAL: + + - ``weyl_character_ring`` -- a WeylCharacterRing of Cartan Type `[X, r]` + - ``depth`` -- an upper bound for `k` determining how many terms to give (default 5) - - ``wcring`` -- a WeylCharacterRing of Cartan Type `[X, r]` - - ``depth`` -- an upper bound for `k` determining how many terms to give. + If the parameter weyl_character_ring is omitted, the ring may be recovered + as the parent of one of the branched coefficients. EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: A2 = WeylCharacterRing("A2",style="coroots") - sage: v.branch(A2, 5) + sage: v.branch() [A2(0,0), A2(1,1), A2(0,0) + 2*A2(1,1) + A2(2,2), @@ -805,7 +807,9 @@ def branch(self, wcring, depth): 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] """ - if wcring.cartan_type() != self.cartan_type().classical(): + if weyl_character_ring is None: + weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") + if weyl_character_ring.cartan_type() != self.cartan_type().classical(): raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) def next_level(x): ret = [] @@ -820,7 +824,7 @@ def next_level(x): return ret hwv = (tuple([0 for i in self._index_set]), 1) terms = RecursivelyEnumeratedSet([hwv], next_level) - fw = wcring.fundamental_weights() + fw = weyl_character_ring.fundamental_weights() P = self.weight_lattice() ret = [] for l in range(depth+1): @@ -833,5 +837,5 @@ def next_level(x): ldict[contr] += x[1] else: ldict[contr] = x[1] - ret.append(wcring.char_from_weights(ldict)) + ret.append(weyl_character_ring.char_from_weights(ldict)) return ret From 49dc92ba66a2196af71ba62ef475e0403e43ac11 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Wed, 22 Apr 2015 15:30:52 +0200 Subject: [PATCH 450/665] Non integral exponents for variable is not permitted --- .../polynomial_integer_dense_flint.pyx | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index aae1b3f56e0..7135ef9eb61 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -55,6 +55,8 @@ from sage.libs.flint.fmpz_poly cimport fmpz_poly_reverse, fmpz_poly_revert_serie from sage.libs.flint.ntl_interface cimport fmpz_set_ZZ, fmpz_poly_set_ZZX, fmpz_poly_get_ZZX from sage.libs.ntl.ntl_ZZX_decl cimport * +from cpython.number cimport PyNumber_AsSsize_t + cdef extern from "limits.h": long LONG_MAX @@ -861,7 +863,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sig_off() return x - def __pow__(Polynomial_integer_dense_flint self, int exp, ignored): + def __pow__(Polynomial_integer_dense_flint self, exp, ignored): """ EXAMPLES:: @@ -889,15 +891,29 @@ cdef class Polynomial_integer_dense_flint(Polynomial): Traceback (most recent call last): ... ZeroDivisionError: negative exponent in power of zero + + Check that :trac:`18278` is fixed:: + + sage: R. = ZZ[] + sage: x^(1/2) + Traceback (most recent call last): + ... + TypeError: non-integral exponents not supported """ - cdef long nn = exp + cdef Py_ssize_t nn cdef Polynomial_integer_dense_flint res = self._new() + + try: + nn = PyNumber_AsSsize_t (exp, OverflowError) + except TypeError: + raise TypeError("non-integral exponents not supported") + if self.is_zero(): if exp == 0: fmpz_poly_set_coeff_si(res.__poly, 0, 1) return res elif exp < 0: - raise ZeroDivisionError, "negative exponent in power of zero" + raise ZeroDivisionError("negative exponent in power of zero") else: return res if exp < 0: From 874deac06298703bc9cd9d8354302830739d6089 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 22 Apr 2015 15:40:04 +0200 Subject: [PATCH 451/665] AbstractChannel now inherits from SageObject. Added an alias to transmit method. --- src/sage/coding/channel_constructions.py | 31 +++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 066b205d5d6..43bbfa675be 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -24,6 +24,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.structure.sage_object import SageObject from sage.rings.finite_rings.constructor import GF from sage.misc.prandom import randint, random, random_error_position from sage.modules.free_module_element import vector @@ -97,7 +98,7 @@ def tuple_to_integer(value): -class AbstractChannel(object): +class AbstractChannel(SageObject): r""" Abstract top-class for Channel objects. @@ -191,12 +192,40 @@ def transmit(self, message): Traceback (most recent call last): ... TypeError: Message must be an element of the input space for the given channel + + .. NOTE:: + + One can also call directly ``Chan(message)``, which does the same as ``Chan.transmit(message)`` """ if message in self.input_space(): return self.transmit_unsafe(message) else : raise TypeError("Message must be an element of the input space for the given channel") + def __call__(self, message): + r""" + This is an alias for ``transmit`` method. + With this method, one can transmit a message ``msg`` through a Channel ``Chan`` + by calling ``Chan(msg)`` instead of having to write ``Chan.transmit(msg)``. + See :meth:`transmit` for details. + + EXAMPLES:: + + sage: F = VectorSpace(GF(59), 6) + sage: n_err = 2 + sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: msg = F((4, 8, 15, 16, 23, 42)) + sage: set_random_seed(10) + sage: m1 = Chan(msg) + sage: set_random_seed(10) + sage: m2 = Chan.transmit(msg) + sage: m1 == m2 + True + """ + pass + + __call__ = transmit + def input_space(self): r""" Returns the input space of ``self``. From 8a6b813f295c774689a0f4bd5902e15b387eedd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Wed, 22 Apr 2015 15:44:45 +0200 Subject: [PATCH 452/665] 16659: proofreading, more documentation, minor code style improvements --- .../finite_dimensional_algebras_with_basis.py | 301 ++++++++++++------ 1 file changed, 202 insertions(+), 99 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index fc458f553a9..247e814d99c 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -86,7 +86,7 @@ def radical_basis(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -101,7 +101,7 @@ def radical_basis(self): This algebra belongs to the category of finite dimensional algebras over the rationals:: - sage: A in FiniteDimensionalAlgebrasWithBasis(QQ) + sage: A in Algebras(QQ).FiniteDimensional().WithBasis() True Since the field has characteristic `0`, Maschke's Theorem @@ -133,7 +133,7 @@ def radical_basis(self): ....: self._xbar = R.quotient(I).gen() ....: basis_keys = [self._xbar**i for i in range(F.characteristic())] ....: CombinatorialFreeModule.__init__(self, F, basis_keys, - ....: category=FiniteDimensionalAlgebrasWithBasis(F)) + ....: category=Algebras(F).FiniteDimensional().WithBasis()) ....: def one(self): ....: return self.basis()[self.base_ring().one()] ....: def product_on_basis(self, w1, w2): @@ -222,7 +222,7 @@ def radical(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -277,7 +277,7 @@ def semisimple_quotient(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -333,7 +333,7 @@ def center_basis(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -351,7 +351,7 @@ def center(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -403,7 +403,7 @@ def principal_ideal(self, a, side='left'): right principal ideals, our first example deals with a non commutative algebra:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field @@ -444,10 +444,6 @@ def orthogonal_idempotents_central_mod_rad(self): Return a family of orthogonal idempotents of ``self`` that project on the central orthogonal idempotents of the semisimple quotient. - INPUT: - - - ``self`` -- a finite dimensional algebra - OUTPUT: - a list of orthogonal idempotents obtained by lifting the central @@ -459,22 +455,24 @@ def orthogonal_idempotents_central_mod_rad(self): central orthogonal idempotents of the semisimple quotient `\overline{A}`. - Let `(\overline{e_i})` be a set of central orthogonal idempotents - of the semisimple quotient of `A` and `(e_i)` their lift in `A`. - We recursively construct orthogonal idempotents of `A`: if - `(f_i)_{i < n}` is a set of already constructed orthogonal - idempotent, we then construct `f_n` by lifting the element - `(1 - \sum_{i < n} f_i) e_n (1 - \sum_{i < n} f_i)`. + Namely, let `(\overline{f_i})` be the central orthogonal + idempotents of the semisimple quotient of `A`. We + recursively construct orthogonal idempotents of `A` by the + following procedure: assuming `(f_i)_{i < n}` is a set of + already constructed orthogonal idempotent, we construct + `f_k` by idempotent lifting of `(1-f) g (1-f)`, where `g` + is any lift of `\overline{e_k}` and `f=\sum_{iy and b:x->y) over Rational Field @@ -496,13 +494,15 @@ def orthogonal_idempotents_central_mod_rad(self): 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] + sage: sum(orth) == 1 + True sage: all(e*e == e for e in orth) True - sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) + sage: all(e*f == 0 and f*e == 0 for e in orth for f in orth if e != f) True - We construct the minimal orthogonal idempotents of the `0`-Hecke - monoid algebra:: + We construct orthogonal idempotents for the `0`-Hecke + algebra:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: W = WeylGroup(['A', 3]); W.rename("W") @@ -512,72 +512,75 @@ def orthogonal_idempotents_central_mod_rad(self): A submonoid of (Maps from W to itself) with 3 generators sage: A = M.algebra(QQ) sage: orth = A.orthogonal_idempotents_central_mod_rad() + sage: sum(orth) == 1 + True sage: all(e*e == e for e in orth) True - sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) + sage: all(e*f == 0 and f*e == 0 for e in orth for f in orth if e!= f) True """ - Aquo = self.semisimple_quotient() one = self.one() # Construction of the orthogonal idempotents - idems = [] - f = 0 - for g in Aquo.central_orthogonal_idempotents(): - idems.append(self.idempotent_lift((one - f) * g.lift() * (one - f))) - f = f + idems[-1] - return idems + idempotents = [] + f = self.zero() + for g in self.semisimple_quotient().central_orthogonal_idempotents(): + fi = self.idempotent_lift((one - f) * g.lift() * (one - f)) + idempotents.append(fi) + f = f + fi + return idempotents def idempotent_lift(self, x): r""" - Return an idempotent of ``self`` which projection on the semisimple - quotient is the same as `x`. + Lift an idempotent of the semisimple quotient into an idempotent of ``self``. - Let `\pi` be the projection `A \rightarrow \overline{A}` on the - quotient by the radical. + Let `A` be this finite dimensional algebra and `\pi` be + the projection `A \rightarrow \overline{A}` on its + semisimple quotient. Let `\overline{x}` be an idempotent + of `\overline A`, and `x` any lift thereof in `A`. This + returns an idempotent `e` of `A` such that `\pi(e)=\pi(x)` + and `e` is a polynomial in `x`. INPUT: - 1. either `x` -- an idempotent of the semisimple quotient of `A` - 2. or `x` -- an element of an algebra `A` which project on an - idempotent element of the semisimple quotient of `A` - - OUTPUT: + - `x` -- an element of `A` that projects on an idempotent + `\overline x` of the semisimple quotient of `A`. + Alternatively one may give as input the idempotent + `\overline{x}`, in which case some lift thereof will be + taken for `x`. - 1. if `x` is in the semisimple quotient of `A`, return an idempotent - `e` such that `\pi(e) = x`. - 2. if `x` is in `A`, return the unique idempotent `e` of `A` such - that `\pi(e) = \pi(x)` and `e` is polynomial in `x`. + OUTPUT: the idempotent `e` of ``self`` ALGORITHM: - For `\overline{e}` an idempotent of `\overline{A}`, we construct `e - \in A` idempotent such that `\pi(e) = \overline{e}`. Namely, we - find an element of `A` for which the projection on `\overline{A}` - is `\overline{e}` and then iterate the formula `1 - (1 - e^2)^2` - until having an idempotent. + Iterate the formula `1 - (1 - x^2)^2` until having an + idempotent. See [CR62] for correctness and termination proofs. EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: S = A.semisimple_quotient() sage: A.idempotent_lift(S.basis()['x']) x sage: A.idempotent_lift(A.basis()['y']) y + + .. TODO:: + + Add some non trivial example """ if not self.is_parent_of(x): x = x.lift() p = self.semisimple_quotient().retract(x) - if p*p != p: + if p * p != p: raise ValueError("%s does not retract to an idempotent."%p) - xOld = None + x_prev = None one = self.one() - while x != xOld: + while x != x_prev: tmp = x x = (one - (one - x**2)**2) - xOld = tmp + x_prev = tmp return x @cached_method @@ -585,22 +588,86 @@ def cartan_invariants_matrix(self): r""" Return the Cartan invariants matrix of the algebra. - OUTPUT: + OUTPUT: a matrix of non negative integers - - The Cartan invariants matrix of the algebra. + Let `A` be this finite dimensional algebra and + `(S_i)_{i\in I}` be representatives of the right simple + modules of `A`. Note that their adjoints `S_i^*` are + representatives of the right simple modules. - EXAMPLES:: + Let `(P^L_i)_{i\in I}` and `(P^R_i)_{i\in I}` be + respectively representatives of the corresponding + indecomposable projective left and right modules of `A`. + In particular, we assume that the indexing is consistent + so that `S_i^*=\operatorname{top} P^L_i` and + `S_i=\operatorname{top} P^R_i`. + + The *Cartan invariant matrix* `(C_{i,j})_{i,j\in I}` is a + matrix of non negative integers that encodes much of the + representation theory of `A`; namely: + + - `C_{i,j}` counts how many times `S_i^*\otimes S_j` + appears as composition factor of `A` seen as a bimodule + over itself; + + - `C_{i,j}=\dim Hom_A(P^R_j, P^R_i)`; + + - `C_{i,j}` counts how many times `S_j` appears as + composition factor of `P^R_i`; + + - `C_{i,j}=\dim Hom_A(P^L_i, P^L_j)`; + + - `C_{i,j}` counts how many times `S_i^*` appears as + composition factor of `P^L_j`. + + In the commutative case, the Cartan invariant matrix is + diagonal. In the context of solving systems of + multivariate polynomial equations of dimension zero, `A` + is the quotient of the polynomial ring by the ideal + generated by the equations, the simple modules correspond + to the roots, and the numbers `C_{i,i}` give the + multiplicities of those roots. + + .. NOTE:: + + For simplicity, the current implementation, assumes + that the index set `I` is of the form + `\{0,\dots,n-1\}`. Better indexations will be possible + in the future. + + ALGORITHM: + + The Cartan invariant matrix of `A` is computed from the + dimension of the summands of its peirce decomposition. + + .. SEEALSO:: + + - :meth:`peirce_decomposition` + + EXAMPLES: + + For a semisimple algebra, in particular for group algebras + in chararacteristic zero, the Cartan invariants matrix is + the identity:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.cartan_invariants_matrix() - [1 0] - [2 1] sage: A3 = SymmetricGroup(3).algebra(QQ) sage: A3.cartan_invariants_matrix() [1 0 0] [0 1 0] [0 0 1] - sage: Z12 = Monoids().Finite().example() + + For the path algebra of a quiver, the Cartan invariants + matrix counts the number of paths between two vertices:: + + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() + sage: A.cartan_invariants_matrix() + [1 0] + [2 1] + + In the commutative case, the Cartan invariant matrix is diagonal:: + + sage: Z12 = Monoids().Finite().example(); Z12 + An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0 0] @@ -616,12 +683,12 @@ def cartan_invariants_matrix(self): With the 0-Hecke monoid algebra:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup - sage: W = WeylGroup(['A', 3]); W.rename("W") + sage: W = SymmetricGroup(4); W.rename("W") sage: ambient_monoid = FiniteSetMaps(W, action="right") sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()); M + sage: H4 = ambient_monoid.submonoid(pi); H4 A submonoid of (Maps from W to itself) with 3 generators - sage: A = M.algebra(QQ) + sage: A = H4.algebra(QQ) sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0] [0 1 1 1 0 0 0 0] @@ -632,10 +699,10 @@ def cartan_invariants_matrix(self): [0 0 0 0 1 1 1 0] [0 0 0 0 0 0 0 1] """ - Aquo = self.semisimple_quotient() - orth_quo = Aquo.central_orthogonal_idempotents() + A_quo = self.semisimple_quotient() + orth_quo = A_quo.central_orthogonal_idempotents() # Dimension of simple modules - dimSimples = [sqrt(Aquo.principal_ideal(e).dimension()) for e in + dimSimples = [sqrt(A_quo.principal_ideal(e).dimension()) for e in orth_quo] # Orthogonal idempotents orth = self.orthogonal_idempotents_central_mod_rad() @@ -668,7 +735,7 @@ def projective_isotypics(self, side='left'): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: projs = A.projective_isotypics(side="left"); projs [Free module generated by {0, 1, 2} over Rational Field, Free module generated by {0} over Rational Field] @@ -703,7 +770,7 @@ def peirce_summand(self, ei, ej): EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: idemp = A.orthogonal_idempotents_central_mod_rad() sage: A.peirce_summand(idemp[1], idemp[0]) Free module generated by {0, 1} over Rational Field @@ -725,49 +792,85 @@ def peirce_summand(self, ei, ej): already_echelonized=True) - def peirce_decomposition(self, list_idempotents=None, check=True): + def peirce_decomposition(self, idempotents=None, check=True): r""" - Return the Peirce decomposition of ``self``. + Return a Peirce decomposition of ``self``. + + Let `(e_i)` be a collection of orthogonal idempotents of + `A` with sum `1`. The *Peirce decomposition* of `A` is the + decomposition of `A` into the direct sum of the subspaces + `e_i A e_j`. + + With the default collection of orthogonal idempotents, one has - Let `(e_i)` be a set of orthogonal idempotents of `A` with sum `1`, - then `A` is the direct sum of the subspaces `e_i A e_j`. + .. MATH:: + + \dim e_i A e_j = C_{i,j} \dim S_i \dim S_j + + where `(S_i)_i` are the simple modules of `A` and + `C_{i,j}` is the Cartan invariants matrix. INPUT: - - ``list_idempotents`` -- (default: None) A list of orthogonal - idempotents of the algebra. By default, the list of orthogonal - idempotents will be lifted from the central orthogonal - idempotents of the semisimple quotient. - - ``check`` -- (default: True) If set to True ``list_idempotents`` - is checked to be orthogonal. + - ``idempotents`` -- a finite collection of orthogonal + idempotents of the algebra that sum to `1` (default: the + idempotents returned by + :meth:`orthogonal_idempotents_central_mod_rad`) + + - ``check`` -- whether to check that the idempotents are + indeed orthogonal (default: True) OUTPUT: - - The list of subspaces `e_i A e_j`, where `e_i` and `e_j` run + The subspaces `e_i A e_j`, where `e_i` and `e_j` run through ``list_idempotents``. - .. SEEALSO:: :meth:`orthogonal_idempotents_central_mod_rad` + .. SEEALSO:: + + - :meth:`orthogonal_idempotents_central_mod_rad` + - :meth:`cartan_invariants_matrix` EXAMPLES:: - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.peirce_decomposition() - [Free module generated by {0} over Rational Field, Free module - generated by {} over Rational Field, Free module generated by - {0, 1} over Rational Field, Free module generated by {0} over - Rational Field] + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field + sage: A.orthogonal_idempotents_central_mod_rad() + [y, x] + sage: decomposition = A.peirce_decomposition(); decomposition + [Free module generated by {0} over Rational Field, + Free module generated by {} over Rational Field, + Free module generated by {0, 1} over Rational Field, + Free module generated by {0} over Rational Field] + sage: [[x.lift() for x in summand.basis()] + ....: for summand in decomposition] + [[y], + [], + [a, b], + [x]] + + .. TODO:: + + - Extract a method that tests whether a collection of + elements form a decomposition of the identity into + orthogonal idempotents. + + - Specify the order in which the summands are returned, + or return a list of list or a dictionary. """ - import itertools - if list_idempotents is None: - list_idempotents = self.orthogonal_idempotents_central_mod_rad() + if idempotents is None: + idempotents = self.orthogonal_idempotents_central_mod_rad() if check: - if not (all(e*e == e for e in list_idempotents) and - all(e*f == f*e and e*f == 0 for e, f in - itertools.product(list_idempotents, repeat=2) if e != f)): - raise ValueError("Not an orthogonal list of idempotents.") - return [self.peirce_summand(ei, ej) for ei, ej in - itertools.product(list_idempotents, repeat=2)] - + if not (self.sum(idempotents) == self.one() and + all(e*e == e for e in idempotents) and + all(e*f == 0 and f*e == 0 + for e in idempotents + for f in idempotents if f != e)): + raise ValueError("Not a collection of orthogonal idempotents that sum to 1") + return [self.peirce_summand(ei, ej) + for ei in idempotents + for ej in idempotents] class ElementMethods: From e652a098c9d87cf7ec2e78e676ef47f1050aa3c3 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Wed, 22 Apr 2015 15:55:03 +0200 Subject: [PATCH 453/665] Remove PID restriction for polynomial is_squarefree() --- .../rings/polynomial/polynomial_element.pyx | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2e3c846c0af..023c4f0138c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6404,9 +6404,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (f*(x^2-5)).is_squarefree() False - A generic implementation is available for polynomials defined over - principal ideal domains of characteristic 0; the algorithm relies on - gcd computations:: + A generic implementation is available, which relies on gcd + computations:: sage: R. = ZZ[] sage: (2*x).is_squarefree() @@ -6418,6 +6417,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: R(0).is_squarefree() False + This can obviously fail if the ring does not implement ``gcd()``:: + sage: S. = QQ[] sage: R. = S[] sage: (2*x*y).is_squarefree() # R does not provide a gcd implementation @@ -6427,8 +6428,8 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: (2*x*y^2).is_squarefree() False - Over principal ideal domains of positive characteristic, we compute the - square-free decomposition or a full factorization depending on which is + In positive characteristic, we compute the square-free + decomposition or a full factorization, depending on which is available:: sage: K. = FunctionField(GF(3)) @@ -6462,12 +6463,24 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: c = f.content() sage: (f/c).is_squarefree() True + + If the base ring is not an integral domain, the question is not + mathematically well-defined:: + + sage: R. = IntegerModRing(9)[] + sage: pol = (x + 3)*(x + 6); pol + x^2 + sage: pol.is_squarefree() + Traceback (most recent call last): + ... + TypeError: is_squarefree() is not defined for polynomials over Ring of integers modulo 9 """ - if self.parent().base_ring() not in sage.categories.principal_ideal_domains.PrincipalIdealDomains(): - raise NotImplementedError("is_squarefree() is only implemented for polynomials over principal ideal domains") + B = self.parent().base_ring() + if B not in sage.categories.integral_domains.IntegralDomains(): + raise TypeError("is_squarefree() is not defined for polynomials over {}".format(B)) # a square-free polynomial has a square-free content - if not self.parent().base_ring().is_field(): + if not B.is_field(): content = self.content() if content not in self.parent().base_ring(): content = content.gen() @@ -6479,7 +6492,7 @@ cdef class Polynomial(CommutativeAlgebraElement): return True # for characteristic zero rings, square-free polynomials have to be separable - if self.parent().characteristic().is_zero(): + if B.characteristic().is_zero(): return False # over rings of positive characteristic, we rely on the square-free decomposition if available From 1b831c1be4f01e0b25b9c05c822ab4334b4c41e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Apr 2015 16:25:32 +0200 Subject: [PATCH 454/665] trac #16352 'graded' in src/sage/categories/highest_weight_crystals.py --- src/sage/categories/highest_weight_crystals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 6f40fe1888d..d16ea768639 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -203,7 +203,7 @@ def __iter__(self, index_set=None, max_depth = float("inf")): from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet return RecursivelyEnumeratedSet(self.module_generators, lambda x: [x.f(i) for i in index_set], - structure=None, + structure='graded', max_depth=max_depth).breadth_first_search_iterator() @cached_method From 1a1a6ccc6c1e731c2506cd527c7de6e331af4b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Apr 2015 16:30:35 +0200 Subject: [PATCH 455/665] trac #16352 'graded' in root_lattice_realizations.py --- src/sage/combinat/root_system/root_lattice_realizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 0b9da663e35..fc6c5209902 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -691,7 +691,7 @@ def positive_roots(self, index_set=None): index_set = tuple(self.cartan_type().index_set()) return RecursivelyEnumeratedSet([self.simple_root(i) for i in index_set], attrcall('pred', index_set=index_set), - structure=None, enumeration='breadth') + structure='graded', enumeration='breadth') @cached_method def nonparabolic_positive_roots(self, index_set = None): From 3fa0c49d1b62fd5b9de1ffd88b4e4dc70ce544b8 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 22 Apr 2015 16:50:55 +0200 Subject: [PATCH 456/665] 16659: documentation references --- .../categories/finite_dimensional_algebras_with_basis.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 9fc1e5470b0..5fca2b3ef8d 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -466,7 +466,7 @@ def orthogonal_idempotents_central_mod_rad(self): idempotent, we then construct `f_n` by lifting the element `(1 - \sum_{i < n} f_i) e_n (1 - \sum_{i < n} f_i)`. - See [CR62] for correctness and termination proofs. + See [CR62]_ for correctness and termination proofs. .. SEEALSO:: :meth:`idempotent_lift` @@ -501,8 +501,8 @@ def orthogonal_idempotents_central_mod_rad(self): sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orth, orth) if e!= f) True - We construct the minimal orthogonal idempotents of the `0`-Hecke - monoid algebra:: + We construct orthogonal idempotents of the algebra of the `0`-Hecke + monoid:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: W = WeylGroup(['A', 3]); W.rename("W") @@ -556,7 +556,7 @@ def idempotent_lift(self, x): is `\overline{e}` and then iterate the formula `1 - (1 - e^2)^2` until having an idempotent. - See [CR62] for correctness and termination proofs. + See [CR62]_ for correctness and termination proofs. EXAMPLES:: From 5f31c5cef52b9b0bdbd905f4ff132e344446e766 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Wed, 22 Apr 2015 17:04:22 +0200 Subject: [PATCH 457/665] Changed name of random_error_position to sample_range, updated documentation, propaged naiming change. Removed some whitespaces --- src/sage/coding/channel_constructions.py | 26 ++++++++-------- src/sage/misc/prandom.py | 39 +++++++++++++----------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 43bbfa675be..9933323d044 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -26,7 +26,7 @@ from sage.structure.sage_object import SageObject from sage.rings.finite_rings.constructor import GF -from sage.misc.prandom import randint, random, random_error_position +from sage.misc.prandom import randint, random, sample_range from sage.modules.free_module_element import vector from sage.misc.abstract_method import abstract_method from sage.combinat.cartesian_product import CartesianProduct @@ -37,9 +37,6 @@ def random_error_vector(n, F, error_positions): Return a vector of length ``n`` over ``F`` filled with random non-zero coefficients at the positions given by ``error_positions``. - This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. - .. NOTE:: This is a helper function, which should only be used when implementing new channels. @@ -56,6 +53,11 @@ def random_error_vector(n, F, error_positions): - a vector of ``F`` + AUTHORS: + + This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. + EXAMPLES:: sage: sage.coding.channel_constructions.random_error_vector(5, GF(2), [1,3]) @@ -254,7 +256,7 @@ def output_space(self): Vector space of dimension 6 over Finite Field of size 59 """ return self._output_space - + @abstract_method def transmit_unsafe(self, message): r""" @@ -314,7 +316,7 @@ class StaticErrorRateChannel(AbstractChannel): def __init__(self, space, number_errors): r""" TESTS: - + If the number of errors exceeds the dimension of the input space, it will return an error:: @@ -363,7 +365,7 @@ def _latex_(self): sage: Chan._latex_() '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' """ - if not hasattr(self.number_errors(), "__iter__"): + if not hasattr(self.number_errors(), "__iter__"): return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ % self.number_errors() else: @@ -376,7 +378,7 @@ def __eq__(self, other): Checks if ``self`` is equal to ``other``. EXAMPLES:: - + sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 sage: Chan1 = channels.StaticErrorRateChannel(F, n_err) @@ -416,9 +418,9 @@ def transmit_unsafe(self, message): V = self.input_space() n = V.dimension() error_vector = random_error_vector(n, V.base_ring(),\ - random_error_position(n, number_errors)) + sample_range(n, number_errors)) return message + error_vector - + def number_errors(self): r""" Returns the number of errors created by ``self``. @@ -612,9 +614,9 @@ def transmit_unsafe(self, message): V = self.input_space() n = V.dimension() - erroneous_positions = random_error_position(n,\ + erroneous_positions = sample_range(n,\ number_errors + number_erasures) - error_split = random_error_position(number_errors + number_erasures,\ + error_split = sample_range(number_errors + number_erasures,\ number_errors) error_positions = [ erroneous_positions[i] for i in\ range(number_errors + number_erasures) if i in error_split ] diff --git a/src/sage/misc/prandom.py b/src/sage/misc/prandom.py index d2d172a5464..115ddcb176a 100644 --- a/src/sage/misc/prandom.py +++ b/src/sage/misc/prandom.py @@ -177,38 +177,41 @@ def sample(population, k): """ return _pyrand().sample(population, k) -def random_error_position(n , number_errors): +def sample_range(n , k): r""" - Returns a list of exactly ``number_errors`` unique random numbers between 0 and ``n-1``. - This function was taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. + Returns a subset of [0, ..., n-1] of size k with uniform probability. INPUT: - - ``number_errors`` -- the number of elements in the list - - - ``n`` -- upper bound for the elements of the list + - ``n``, ``k`` -- integers OUTPUT: - - A list of integers + - An ordered list of integers + + AUTHORS: + + This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) + and was written by Johan Nielsen. EXAMPLES:: - sage: random_error_position(6, 2) # random + sage: sample_range(6, 2) # random [1, 4] - sage:set_random_seed(10) - sage: random_error_position(10,4) - [0, 2, 4, 9] + sage: set_random_seed(10) + sage: sample_range(10,4) + [6, 7, 8, 9] """ - error_position = [] + n = int(n) + k = int(k) + ordered_set = [] i = 0 - while i < n and number_errors > 0: - if random() < number_errors/(n-i): - error_position.append(i) - number_errors -= 1 + while i < n and k > 0: + if random() < k/(n-i): + ordered_set.append(i) + k -= 1 i += 1 - return error_position + return ordered_set def random(): From 3a625818273d2f13547e8399c803405c14935a81 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 22 Apr 2015 17:20:53 +0200 Subject: [PATCH 458/665] 16659: add test for orthogonal idempotents summing to one --- .../finite_dimensional_algebras_with_basis.py | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 772f32ac23e..cff925a8d47 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -508,9 +508,7 @@ def orthogonal_idempotents_central_mod_rad(self): sage: W = WeylGroup(['A', 3]); W.rename("W") sage: ambient_monoid = FiniteSetMaps(W, action="right") sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: M = AutomaticSemigroup(pi, one=ambient_monoid.one()); M - A submonoid of (Maps from W to itself) with 3 generators - sage: A = M.algebra(QQ) + sage: A = AutomaticSemigroup(pi, one=ambient_monoid.one()).algebra(QQ) sage: orth = A.orthogonal_idempotents_central_mod_rad() sage: sum(orth) == 1 True @@ -817,8 +815,8 @@ def peirce_decomposition(self, idempotents=None, check=True): idempotents returned by :meth:`orthogonal_idempotents_central_mod_rad`) - - ``check`` -- whether to check that the idempotents are - indeed orthogonal (default: True) + - ``check`` -- (default:True) whether to check that the idempotents + are indeed orthogonal OUTPUT: @@ -862,16 +860,46 @@ def peirce_decomposition(self, idempotents=None, check=True): if idempotents is None: idempotents = self.orthogonal_idempotents_central_mod_rad() if check: - if not (self.sum(idempotents) == self.one() and - all(e*e == e for e in idempotents) and - all(e*f == 0 and f*e == 0 - for e in idempotents - for f in idempotents if f != e)): + if not self.is_orthogonal_idempotents(idempotents): raise ValueError("Not a collection of orthogonal idempotents that sum to 1") return [self.peirce_summand(ei, ej) for ei in idempotents for ej in idempotents] + def is_orthogonal_idempotents(self, l): + r""" + Return True of ``l`` is a list of orthogonal idempotents with sum + one. + + INPUT: + + - ``l`` -- a list of elements of ``self`` + + OUTPUT: + + - True if ``l`` is a list of orthogonal idempotents with sum `1`, + False otherwise. + + EXAMPLES:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() + sage: A.is_orthogonal_idempotents(A.orthogonal_idempotents_central_mod_rad()) + True + + With the algebra of the `0`-Hecke monoid:: + + sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup + sage: W = WeylGroup(['A', 4]); W.rename("W") + sage: ambient_monoid = FiniteSetMaps(W, action="right") + sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) + sage: A = AutomaticSemigroup(pi, one=ambient_monoid.one()).algebra(QQ) + sage: A.is_orthogonal_idempotents(A.orthogonal_idempotents_central_mod_rad()) + True + """ + return (self.sum(l) == self.one() and all(e*e == e for e in l) + and all(e*f == 0 and f*e == 0 for e in l for f in l if f != e) + and sum(l) == self.one()) + class ElementMethods: def to_matrix(self, base_ring=None, action=operator.mul, side='left'): From 34bc684dba05e540085a0d4757438d5c60efb320 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 22 Apr 2015 09:21:13 -0700 Subject: [PATCH 459/665] branch method: doc revision and don't use i --- .../root_system/integrable_representations.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index cb6b9556cbf..a51643843e1 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -791,14 +791,11 @@ def branch(self, weyl_character_ring=None, depth=5): - ``weyl_character_ring`` -- a WeylCharacterRing of Cartan Type `[X, r]` - ``depth`` -- an upper bound for `k` determining how many terms to give (default 5) - If the parameter weyl_character_ring is omitted, the ring may be recovered - as the parent of one of the branched coefficients. - EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: v.branch() + sage: b = v.branch(); b [A2(0,0), A2(1,1), A2(0,0) + 2*A2(1,1) + A2(2,2), @@ -806,6 +803,12 @@ def branch(self, weyl_character_ring=None, depth=5): 4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1), 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] + If the parameter weyl_character_ring is omitted, the ring may be recovered + as the parent of one of the branched coefficients:: + + sage: A2 = b[0].parent(); A2 + The Weyl Character Ring of Type A2 with Integer Ring coefficients + """ if weyl_character_ring is None: weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") @@ -813,16 +816,16 @@ def branch(self, weyl_character_ring=None, depth=5): raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) def next_level(x): ret = [] - for i in self._index_set: + for j in self._index_set: t = list(x[0]) - t[i] += 1 + t[j] += 1 t = tuple(t) u = self.to_weight(t) m = self.m(t) if m > 0 and t[0] <= depth: ret.append((t,m)) return ret - hwv = (tuple([0 for i in self._index_set]), 1) + hwv = (tuple([0 for j in self._index_set]), 1) terms = RecursivelyEnumeratedSet([hwv], next_level) fw = weyl_character_ring.fundamental_weights() P = self.weight_lattice() @@ -832,7 +835,7 @@ def next_level(x): ldict = {} for x in lterms: mc = P(self.to_weight(x[0])).monomial_coefficients() - contr = sum(fw[i]*mc.get(i,0) for i in self._index_set_classical).coerce_to_sl() + contr = sum(fw[j]*mc.get(j,0) for j in self._index_set_classical).coerce_to_sl() if ldict.has_key(contr): ldict[contr] += x[1] else: From e27535b0a4ddb3276c5b2a8875cb0e7105b87ad4 Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Tue, 27 Jan 2015 21:57:28 +0100 Subject: [PATCH 460/665] #17682: More generic shared library file extension --- src/sage/misc/cython.py | 7 ++----- src/sage/misc/sageinspect.py | 10 ++++++++-- src/sage_setup/clean.py | 11 ++++------- src/sage_setup/find.py | 6 ++++-- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 5094c3c2143..ed82cd59200 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -543,11 +543,8 @@ def cython(filename, verbose=False, compile_message=False, if create_local_so_file: # Copy from lib directory into local directory - libext = 'so' - UNAME = os.uname()[0].lower() - if UNAME[:6] == 'cygwin': - libext = 'dll' - cmd = 'cp %s/%s.%s %s'%(build_dir, name, libext, os.path.abspath(os.curdir)) + from sage.misc.sageinspect import generic_so_extension + cmd = 'cp %s/%s%s %s'%(build_dir, name, generic_so_extension, os.path.abspath(os.curdir)) if os.system(cmd): raise RuntimeError("Error making local copy of shared object library for {}".format(filename)) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index aa3c6a07acc..6c9aec20b6d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -118,9 +118,15 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return import os import tokenize import types +import sys EMBEDDED_MODE = False from sage.env import SAGE_SRC +if sys.platform == 'cygwin': + generic_so_extension = os.path.extsep + 'dll' +else: + generic_so_extension = os.path.extsep + 'so' + def isclassinstance(obj): r""" Checks if argument is instance of non built-in class @@ -1175,8 +1181,8 @@ def sage_getfile(obj): # No go? fall back to inspect. sourcefile = inspect.getabsfile(obj) - if sourcefile.endswith(os.path.extsep+'so'): - return sourcefile[:-3]+os.path.extsep+'pyx' + if sourcefile.endswith(generic_so_extension): + return sourcefile[:-len(generic_so_extension)]+os.path.extsep+'pyx' return sourcefile def sage_getargspec(obj): diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index 7b6943b56dc..3ba50c80e61 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -80,17 +80,14 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module extension modules:: sage: stale_iter = _find_stale_files(SAGE_LIB, python_packages, python_modules, []) + sage: from sage.misc.sageinspect import generic_so_extension sage: for f in stale_iter: - ....: if f.endswith('.so'): continue + ....: if f.endswith(generic_so_extension): continue ....: print('Found stale file: ' + f) """ PYMOD_EXTS = (os.path.extsep + 'py', os.path.extsep + 'pyc') - import sys - if sys.platform == 'cygwin': - LIBEXT = 'dll' - else: - LIBEXT = 'so' - CEXTMOD_EXTS = (os.path.extsep + LIBEXT,) + from sage.misc.sageinspect import generic_so_extension + CEXTMOD_EXTS = (generic_so_extension,) INIT_FILES= map(lambda x: '__init__' + x, PYMOD_EXTS) module_files = installed_files_by_module(site_packages, ['sage', 'sage_setup']) diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index d208364601b..41a8a23a16a 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -100,8 +100,10 @@ def installed_files_by_module(site_packages, modules=('sage',)): sage: from site import getsitepackages sage: site_packages = getsitepackages()[0] sage: files_by_module = installed_files_by_module(site_packages) - sage: files_by_module['sage.structure.sage_object'] - {'sage/structure/sage_object.so'} + sage: from sage.misc.sageinspect import generic_so_extension + sage: files_by_module['sage.structure.sage_object'] == \ + ....: {'sage/structure/sage_object' + generic_so_extension} + True sage: sorted(files_by_module['sage.structure']) ['sage/structure/__init__.py', 'sage/structure/__init__.pyc'] From 4286d976916a6a6894e51d50e37e70e8b30736e8 Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Sat, 31 Jan 2015 12:16:46 +0100 Subject: [PATCH 461/665] Ticket #17682: add generic extension in cython caching --- src/sage/misc/cython.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index ed82cd59200..7802f447c02 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -378,12 +378,13 @@ def cython(filename, verbose=False, compile_message=False, # There is already a module here. Maybe we do not have to rebuild? # Find the name. if use_cache: - prev_so = [F for F in os.listdir(build_dir) if F[-3:] == '.so'] + from sage.misc.sageinspect import generic_so_extension + prev_so = [F for F in os.listdir(build_dir) if F[-len(generic_so_extension):] == generic_so_extension] if len(prev_so) > 0: prev_so = prev_so[0] # should have length 1 because of deletes below if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(build_dir, prev_so)): # We do not have to rebuild. - return prev_so[:-3], build_dir + return prev_so[:-len(generic_so_extension)], build_dir else: os.makedirs(build_dir) for F in os.listdir(build_dir): From c8dcabb8de4e28dacec9bdb2160bf1e45795f709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 20:42:11 +0200 Subject: [PATCH 462/665] Adding a reference to the symmetric group in the documentation of the BubbleSortGraph. --- src/sage/graphs/generators/families.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 45d416ac587..c2f10fb09d7 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -364,13 +364,18 @@ def BubbleSortGraph(n): r""" Returns the bubble sort graph `B(n)`. - The vertices of the bubble sort graph are the set of permutations on - `n` symbols. Two vertices are adjacent if one can be obtained from the - other by swapping the labels in the `i`-th and `(i+1)`-th positions for - `1 \leq i \leq n-1`. In total, `B(n)` has order `n!`. Thus, the order - of `B(n)` increases according to `f(n) = n!`. - - The bubble sort graph is the underlying graph of the permutahedron. + The vertices of the bubble sort graph are the set of permutations + on `n` symbols. Two vertices are adjacent if one can be obtained + from the other by swapping the labels in the `i`-th and `(i+1)`-th + positions for `1 \leq i \leq n-1`. In total, `B(n)` has order + `n!`. Thus, the order of `B(n)` increases according to `f(n) = + n!`. Swapping two labels as described previously corresponds to + multiplying on the right the permutation corresponding to the node + by an elemantary transposition in the + :class:`~sage.groups.perm_gps.permgroup_named.SymmetricGroup`. + + The bubble sort graph is the underlying graph of the + :meth:`~sage.geometry.polyhedron.library.Polytopes.permutahedron`. INPUT: From 37a33d78102bf971f1a619c1b2c2846e06498017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 20:47:24 +0200 Subject: [PATCH 463/665] Typo correction. --- src/sage/geometry/polyhedron/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index a19e4526d9c..b240581b5cf 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -884,7 +884,7 @@ def permutahedron(self, n, project=False): """ Return the standard permutahedron of (1,...,n) - The premutahedron (or permutohedron) is the convex hull of the + The permutahedron (or permutohedron) is the convex hull of the permutations of `\{1,\ldots,n\}` seen as vectors. If we take the graph in which the vertices correspond to vertices of the From 4aa37f546ca319a0a97c99d85bf69dcac922be9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 20:49:36 +0200 Subject: [PATCH 464/665] Adding a hyperlink reference to the BubbleSortGraph in the doc. --- src/sage/geometry/polyhedron/library.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index b240581b5cf..bd487f245f4 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -881,14 +881,14 @@ def hypersimplex(self, dim, k, project=False): return Polyhedron(vertices=verts) def permutahedron(self, n, project=False): - """ - Return the standard permutahedron of (1,...,n) + """Return the standard permutahedron of (1,...,n) The permutahedron (or permutohedron) is the convex hull of the permutations of `\{1,\ldots,n\}` seen as vectors. - If we take the graph in which the vertices correspond to vertices of the - polyhedron, and edges to edges, we get the bubble sort graph. + If we take the graph in which the vertices correspond to + vertices of the polyhedron, and edges to edges, we get the + :meth:`~sage.graphs.graph_generators.GraphGenerators.BubbleSortGraph`. INPUT: @@ -925,6 +925,7 @@ def permutahedron(self, n, project=False): sage: perm4 = polytopes.permutahedron(4) sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) True + """ verts = list(itertools.permutations(range(1,n+1))) if project: verts = project_points(*verts) From 7dcbbb624ad5f7b286df95a0e4ff3f4e1ec1d121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 20:55:02 +0200 Subject: [PATCH 465/665] Adding a reference to the SymmetricGroup class. --- src/sage/geometry/polyhedron/library.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index bd487f245f4..346c45de030 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -884,7 +884,10 @@ def permutahedron(self, n, project=False): """Return the standard permutahedron of (1,...,n) The permutahedron (or permutohedron) is the convex hull of the - permutations of `\{1,\ldots,n\}` seen as vectors. + permutations of `\{1,\ldots,n\}` seen as vectors. The edges + between the permutations correspond to multiplication on the + right by an elementary transposition in the + :class:`~sage.groups.perm_gps.permgroup_named.SymmetricGroup`. If we take the graph in which the vertices correspond to vertices of the polyhedron, and edges to edges, we get the From 40172664399f1ed1cab45f529adeb28f58a58672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 22:07:50 +0200 Subject: [PATCH 466/665] Moving code from TESTS to EXAMPLES. --- src/sage/geometry/polyhedron/library.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 346c45de030..b63755d78a2 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -918,17 +918,12 @@ def permutahedron(self, n, project=False): A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24 vertices sage: perm4.plot() Graphics3d Object + sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) + True .. SEEALSO:: * :meth:`~sage.graphs.graph_generators.GraphGenerators.BubbleSortGraph` - - TESTS:: - - sage: perm4 = polytopes.permutahedron(4) - sage: perm4.graph().is_isomorphic(graphs.BubbleSortGraph(4)) - True - """ verts = list(itertools.permutations(range(1,n+1))) if project: verts = project_points(*verts) From c1aae477f9b8eb4acbb638d64524a467351f512f Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 22 Apr 2015 13:08:03 -0700 Subject: [PATCH 467/665] branching rules now completely implemented --- .../root_system/integrable_representations.py | 113 +++++++++++++++--- 1 file changed, 96 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index a51643843e1..db574cde2be 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -59,8 +59,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): lattice and `\rho` is the Weyl vector. Moreover every `\mu` differs from `\Lambda` by an element of the root lattice. ([Kac], Propositions 11.3 and 11.4) such that `\Lambda - \mu` is in the root lattice, then multiplicity - of `\mu` in this representation will be denoted `m(\mu)`. The set of `\mu` - such that the multiplicity + of `\mu` in this representation will be denoted `m(\mu)`. Let `\delta` be the nullroot, which is the lowest positive imaginary root. Then by [Kac], Proposition 11.3 or Corollary 11.9, for fixed `\mu` @@ -176,7 +175,7 @@ def __init__(self, Lam): self._mdict = {tuple(0 for i in self._index_set): 1} self._rho = self._P.rho() self._delta = self._Q.null_root() - # Coerce a classical root into Q + # Coerce a classical root into the root lattice Q from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) self._classical_roots = [from_cl_root(al) for al in self._Q.classical().roots()] @@ -778,19 +777,32 @@ def modular_characteristic(self, mu=None): mu = self.to_weight(n) return m_Lambda-self._inner_pp(mu,mu)/(2*k) - def branch(self, weyl_character_ring=None, depth=5): + def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): """ - If ``self`` is a representation of the untwisted affine Lie algebra of Cartan - type ``[X, r, 1]``, then corresponding to the inclusion of ``[X, r]`` in - ``[X, r, 1]``, there is a branching rule producing a sequence of representations - of type ``[X, r]``. The `k`-th representation of this sequence is the restriction - of all weights in which `\delta` has coefficient `k`. + Removing any node from the extended Dynkin diagram of the affine + Lie algebra results in the Dynkin diagram of a classical Lie + algebra, which is therefore a Lie subalgebra. For example + removing the `0` node from the Dynkin diagram of type ``[X, r, 1]`` + produces the classical Dynkin diagram of ``[X, r]``. + + Thus for each `i` in the index set, we may restrict `self` to + the corresponding classical subalgebra. Of course `self` is + an infinite dimensional representation, but each weight `\mu` + is assigned a grading by the number of times the simple root + `\\alpha_i` appears in `\Lambda-\mu`. Thus the branched + representation is graded and we get sequence of finite-dimensional + representations which this method is able to compute. OPTIONAL: + - ``i`` -- an element of the index set (default 0) - ``weyl_character_ring`` -- a WeylCharacterRing of Cartan Type `[X, r]` + - ``sequence`` -- a dictionary - ``depth`` -- an upper bound for `k` determining how many terms to give (default 5) + In the default case where `i=0`, you do not need to specify anything else, + though you may want to increase the depth if you need more terms. + EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() @@ -809,11 +821,78 @@ def branch(self, weyl_character_ring=None, depth=5): sage: A2 = b[0].parent(); A2 The Weyl Character Ring of Type A2 with Integer Ring coefficients - """ - if weyl_character_ring is None: - weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") - if weyl_character_ring.cartan_type() != self.cartan_type().classical(): - raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) + If `i` is not zero then you should specify the WeylCharacterRing that you + are branching to. This is determined by the Dynkin diagram:: + + sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: v.cartan_type().dynkin_diagram() + O 0 + | + | + O---O=>=O + 1 2 3 + B3~ + + In this example, we observe that removing the `i=2` node from the Dynkin diagram + produces a reducible diagram of type ``A1xA1xA1``. Thus we have a branching + to `\mathfrak{sl}(2)\\times \mathfrak{sl}(2)\\times \mathfrak{sl}(2)`:: + + sage: A1xA1xA1 = WeylCharacterRing("A1xA1xA1",style="coroots") + sage: v.branch(i=2,weyl_character_ring=A1xA1xA1) + [A1xA1xA1(1,0,0), + A1xA1xA1(0,1,2), + A1xA1xA1(1,0,0) + A1xA1xA1(1,2,0) + A1xA1xA1(1,0,2), + A1xA1xA1(2,1,2) + A1xA1xA1(0,1,0) + 2*A1xA1xA1(0,1,2), + 3*A1xA1xA1(1,0,0) + 2*A1xA1xA1(1,2,0) + A1xA1xA1(1,2,2) + 2*A1xA1xA1(1,0,2) + A1xA1xA1(1,0,4) + A1xA1xA1(3,0,0), + A1xA1xA1(2,1,0) + 3*A1xA1xA1(2,1,2) + 2*A1xA1xA1(0,1,0) + 5*A1xA1xA1(0,1,2) + A1xA1xA1(0,1,4) + A1xA1xA1(0,3,2)] + + If the nodes of the two Dynkin diagrams are not in the same order, you + must specify an additional parameter, ``sequence`` which gives a dictionary + to the affine Dynkin diagram to the classical one. + + EXAMPLES:: + + sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: v.cartan_type().dynkin_diagram() + O---O---O=>=O---O + 0 1 2 3 4 + F4~ + sage: A1xC3=WeylCharacterRing("A1xC3",style="coroots") + sage: A1xC3.dynkin_diagram() + O + 1 + O---O=<=O + 2 3 4 + A1xC3 + + Observe that removing the `i=1` node from the ``F4~`` Dynkin diagram + gives the ``A1xC3`` diagram, but the roots are in a different order. + The nodes `0, 2, 3, 4` of ``F4~`` correspond to ``1, 4, 3, 2`` + of ``A1xC3`` and so we encode this in a dictionary:: + + sage: v.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) + [A1xC3(1,0,0,0), + A1xC3(0,0,0,1), + A1xC3(1,0,0,0) + A1xC3(1,2,0,0), + A1xC3(2,0,0,1) + A1xC3(0,0,0,1) + A1xC3(0,1,1,0), + 2*A1xC3(1,0,0,0) + A1xC3(1,0,1,0) + 2*A1xC3(1,2,0,0) + A1xC3(1,0,2,0) + A1xC3(3,0,0,0), + 2*A1xC3(2,0,0,1) + A1xC3(2,1,1,0) + A1xC3(0,1,0,0) + 3*A1xC3(0,0,0,1) + 2*A1xC3(0,1,1,0) + A1xC3(0,2,0,1)] + + """ + if i==0: + if weyl_character_ring is None: + weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") + if weyl_character_ring.cartan_type() != self.cartan_type().classical(): + raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) + if sequence == None: + sequence = {} + for j in self._index_set: + if j < i: + sequence[j] = j+1 + elif j > i: + sequence[j] = j def next_level(x): ret = [] for j in self._index_set: @@ -822,7 +901,7 @@ def next_level(x): t = tuple(t) u = self.to_weight(t) m = self.m(t) - if m > 0 and t[0] <= depth: + if m > 0 and t[i] <= depth: ret.append((t,m)) return ret hwv = (tuple([0 for j in self._index_set]), 1) @@ -831,11 +910,11 @@ def next_level(x): P = self.weight_lattice() ret = [] for l in range(depth+1): - lterms = [x for x in terms if x[0][0] == l] + lterms = [x for x in terms if x[0][i] == l] ldict = {} for x in lterms: mc = P(self.to_weight(x[0])).monomial_coefficients() - contr = sum(fw[j]*mc.get(j,0) for j in self._index_set_classical).coerce_to_sl() + contr = sum(fw[sequence[j]]*mc.get(j,0) for j in self._index_set if j != i).coerce_to_sl() if ldict.has_key(contr): ldict[contr] += x[1] else: From 5b90c9b326967fc8f436771de5ec6f489f8ab8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Chatel?= Date: Wed, 22 Apr 2015 22:12:36 +0200 Subject: [PATCH 468/665] Documentation improvement. Deleting a repetition about the order of the graph and correcting a typo. --- src/sage/graphs/generators/families.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index c2f10fb09d7..ae017efa16a 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -368,10 +368,9 @@ def BubbleSortGraph(n): on `n` symbols. Two vertices are adjacent if one can be obtained from the other by swapping the labels in the `i`-th and `(i+1)`-th positions for `1 \leq i \leq n-1`. In total, `B(n)` has order - `n!`. Thus, the order of `B(n)` increases according to `f(n) = - n!`. Swapping two labels as described previously corresponds to + `n!`. Swapping two labels as described previously corresponds to multiplying on the right the permutation corresponding to the node - by an elemantary transposition in the + by an elementary transposition in the :class:`~sage.groups.perm_gps.permgroup_named.SymmetricGroup`. The bubble sort graph is the underlying graph of the From b04d6c08a52d8a143f7669aa684b4c00ee324333 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 22 Apr 2015 13:53:01 -0700 Subject: [PATCH 469/665] doc revision and error handling --- src/sage/combinat/root_system/integrable_representations.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index db574cde2be..4f7dca28729 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -796,7 +796,7 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): OPTIONAL: - ``i`` -- an element of the index set (default 0) - - ``weyl_character_ring`` -- a WeylCharacterRing of Cartan Type `[X, r]` + - ``weyl_character_ring`` -- a WeylCharacterRing - ``sequence`` -- a dictionary - ``depth`` -- an upper bound for `k` determining how many terms to give (default 5) @@ -881,11 +881,13 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): 2*A1xC3(2,0,0,1) + A1xC3(2,1,1,0) + A1xC3(0,1,0,0) + 3*A1xC3(0,0,0,1) + 2*A1xC3(0,1,1,0) + A1xC3(0,2,0,1)] """ - if i==0: + if i==0 or self.cartan_type()[0] == 'A': if weyl_character_ring is None: weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") if weyl_character_ring.cartan_type() != self.cartan_type().classical(): raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) + elif weyl_character_ring is None: + raise ValueError("""The argument "weyl_character_ring" cannot be omitted if "i != 0" """) if sequence == None: sequence = {} for j in self._index_set: From 7389f197e3466e87c7ad1c230b501b3e012c8ef9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 15:17:44 -0700 Subject: [PATCH 470/665] Added reduced word graph method. --- src/sage/categories/coxeter_groups.py | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 9c42afd4b93..9150f8350da 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -1033,6 +1033,52 @@ def reduced_words(self): for r in (self.apply_simple_reflection(i)).reduced_words() ] + def reduced_word_graph(self): + r""" + Return the reduced word graph of ``self``. + + The reduced word graph of an element `w` in a Coxeter group + is the graph whose vertices are reduced words `R_w` and there + is an `m`-colored edge between `x, y \in R_w` if `x` and `y` + differ by exactly one length `m` braid move. + """ + R = self.reduced_words() + from sage.graphs.graph import Graph + # Special case for when the graph does not contain any edges + if len(R) == 1: + return Graph({tuple(R[0]): []}, immutable=True) + + P = self.parent() + edges = [] + for i,x in enumerate(R): + x = tuple(x) + for y in R[i:]: + y = tuple(y) + # Check that the reduced expressions differ by only + # a single braid move + i = 0 + while i < len(x) and x[i] == y[i]: + i += 1 + if i == len(x): + continue + a, b = x[i], y[i] + I = P.index_set() + m = P.coxeter_matrix()[I.index(a),I.index(b)] + subword = [a,b] * (m // 2) + subword2 = [b,a] * (m // 2) + if m % 2 != 0: + subword.append(a) + subword2.append(b) + if (x[i:i+m] != tuple(subword) + or y[i:i+m] != tuple(subword2) + or x[i+m:] != y[i+m:]): + continue + edges.append([x, y, m]) + G = Graph(edges, immutable=True) + colors = {2: 'blue', 3: 'red', 4: 'green'} + G.set_latex_options(edge_labels=True, color_by_label=lambda x: colors[x]) + return G + def length(self): r""" Returns the length of self, that is the minimal length of From 0cf5be88ef55251e5e032b1f2045dfdec13f8583 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Wed, 22 Apr 2015 15:21:00 -0700 Subject: [PATCH 471/665] minor doc changes --- src/sage/combinat/root_system/integrable_representations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 4f7dca28729..c777231d4a1 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -99,7 +99,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): type `A_3^{(1)}`, then define ``Lambda`` to be the fundamental weights. We find there are 5 maximal dominant weights in irreducible representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, - and we determine their string functions. + and we determine their strings. It was shown in [KacPeterson] that each string is the set of Fourier coefficients of a modular form. @@ -299,7 +299,7 @@ def dual_coxeter_number(self): def __repr__(self): """ - Return a string representation of ``self``. + Return a representation of ``self``. """ return "The Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) From e599d4d5284e5d4e9c69fa8ed6adfe1126323ed0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 15:58:02 -0700 Subject: [PATCH 472/665] Adding doctests because I forgot to save teh file. --- src/sage/categories/coxeter_groups.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 9150f8350da..cc0f4ab07b9 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -1041,6 +1041,18 @@ def reduced_word_graph(self): is the graph whose vertices are reduced words `R_w` and there is an `m`-colored edge between `x, y \in R_w` if `x` and `y` differ by exactly one length `m` braid move. + + EXAMPLES:: + + sage: W = WeylGroup(['A',3], prefix='s') + sage: w0 = W.long_element() + sage: G = w0.reduced_word_graph() + sage: G.num_verts() + 16 + sage: len(w0.reduced_words()) + 16 + sage: G.num_edges() + 18 """ R = self.reduced_words() from sage.graphs.graph import Graph From 5ff5d5a0a7d875290b4cd3a24745166ce05bcf96 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 20:42:10 -0700 Subject: [PATCH 473/665] Some old-fashion tuning. --- src/sage/combinat/partition.py | 13 +++++ src/sage/combinat/sf/macdonald.py | 96 ++++++++++++++++++++----------- src/sage/combinat/sf/sfa.py | 41 ++++++++----- 3 files changed, 101 insertions(+), 49 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index ca886c4e57b..17171f4b3a1 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -641,6 +641,19 @@ def __init__(self, parent, mu): else: raise ValueError("%s is not a valid partition"%repr(mu)) + @cached_method + def __hash__(self): + r""" + Return the hash of ``self``. + + TESTS:: + + sage: P = Partition([4,2,2,1]) + sage: hash(P) == hash(P) + True + """ + return tuple(self._list).__hash__() + def _repr_(self, compact=None): r""" Return a string representation of ``self`` depending on diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 37fab72dc3e..b4ffbf973f2 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -54,8 +54,8 @@ from sage.categories.homset import Hom from sage.categories.modules_with_basis import ModulesWithBasis import sfa -from sage.combinat.partition import Partition, Partitions -from sage.combinat.skew_partition import SkewPartition +from sage.combinat.partition import Partition, Partitions_n, _Partitions +from sage.combinat.skew_partition import SkewPartitions from sage.matrix.all import MatrixSpace from sage.rings.all import QQ from sage.misc.all import prod @@ -664,15 +664,25 @@ def cmunu1(mu, nu): True """ q,t = QQqt.gens() - from sage.combinat.skew_partition import SkewPartition - c = SkewPartition([mu,nu]).cells()[0] - A = prod((t**mu.leg_length(*s) - q**(mu.arm_length(*s)+1)) - / (t**nu.leg_length(*s) - q**(nu.arm_length(*s)+1)) - for s in nu.cells() if s[0] == c[0]) + # The following is equivalent to: + # r,c = SkewPartition([mu,nu]).cells()[0] + for i, val in enumerate(nu): + if val < mu[i]: + r,c = i, val + break + else: + r,c = len(nu), 0 + + if r < len(nu): + A = prod((t**mu.leg_length(r, s) - q**(mu.arm_length(r, s)+1)) + / (t**nu.leg_length(r, s) - q**(nu.arm_length(r, s)+1)) + for s in range(nu[r])) + else: + A = QQqt.one() B = prod((q**mu.arm_length(*s) - t**(mu.leg_length(*s)+1)) / (q**nu.arm_length(*s) - t**(nu.leg_length(*s)+1)) - for s in nu.cells() if s[1] == c[1]) - return A*B + for s in nu.cells() if s[1] == c) + return QQqt(A * B) @cached_function def cmunu(mu, nu): @@ -714,14 +724,27 @@ def cmunu(mu, nu): True """ if not nu: - return 1 + return QQqt.one() if not mu.contains(nu): - return 0 + return QQqt.zero() if mu.size() == nu.size() + 1: return cmunu1(mu, nu) - num = sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu(SkewPartition([al,nu])) - for al in nu.up_list()) - return num / Bmu(SkewPartition([mu,nu])) + + # This is equivalent to: + # Bmu(SkewPartition([outer, inner])) + def Bmu_skew(outer, inner): + inner = list(inner) # This makes a (shallow) copy of inner + inner += [0]*(len(outer)-len(inner)) + q,t = QQqt.gens() + res = QQqt.zero() + for i, val in enumerate(outer): + for j in range(inner[i], val): + res += t**i * q**j + return res + + num = sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu_skew(al, nu) + for al in nu.up()) + return num / Bmu_skew(mu, nu) #Generic MacdonaldPolynomials class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): @@ -1335,11 +1358,12 @@ def _self_to_m(self, x): (-x^2+1)*McdH[2, 1] + McdH[3] """ if self.t: + tinv = ~self.t return self._m._from_dict({ part2: - self._base(sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, - mu)).subs(q=self.q,t=1/self.t) * self.t**mu.weighted_size() - for mu in x.homogeneous_component(d).support())) - for d in range(x.degree()+1) for part2 in Partitions(d) }) + self._base( sum(c * self.t**mu.weighted_size() + * self._Lmunu(part2, mu)(q=self.q, t=tinv) + for mu,c in x if self.degree_on_basis(mu) == d)) + for d in range(x.degree()+1) for part2 in Partitions_n(d) }) else: return self._m(self._self_to_s(x)) @@ -1395,8 +1419,9 @@ def _m_to_self( self, f ): while not g.is_zero(): sprt = g.support() Hmu = mu_to_H(sprt[-1]) - out[fl(sprt[-1])] = self._base(g.coefficient(sprt[-1]) / Hmu.coefficient(sprt[-1])) - g -= out[fl(sprt[-1])] * Hmu + fl_sprt = fl(sprt[-1]) + out[fl_sprt] = self._base(g.coefficient(sprt[-1]) / Hmu.coefficient(sprt[-1])) + g -= out[fl_sprt] * Hmu return self._from_dict(out) class Element(MacdonaldPolynomials_generic.Element): @@ -1482,7 +1507,7 @@ def _s_to_self( self, x ): """ return self._m_to_self(self._m(x)) - def _Lmunu(self, nu, mu ): + def _Lmunu(self, nu, mu): r""" Return the coefficient of `m_\nu` in `{\tilde H}_\mu`. @@ -1524,19 +1549,20 @@ def _Lmunu(self, nu, mu ): """ if not mu: if not nu: - return 1 + return QQqt.one() else: - return 0 + return QQqt.zero() if (mu,nu) in self._self_to_m_cache: return self._self_to_m_cache[(mu,nu)] if len(nu) == 1: - return 1 + return QQqt.one() + short_nu = _Partitions(nu[:-1]) if nu[-1] == 1: - self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu1(mu,ga) * self._Lmunu(Partition(nu[:-1]), ga) - for ga in mu.down_list()) ) - return self._self_to_m_cache[(mu,nu)] - self._self_to_m_cache[(mu,nu)] = QQqt(sum( cmunu(mu,ga) * self._Lmunu(Partition(nu[:-1]), ga) - for ga in Partitions(nu.size()-nu[-1]) if mu.contains(ga) )) + self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu1(mu,ga) * self._Lmunu(short_nu, ga) + for ga in mu.down()) ) + else: + self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu(mu,ga) * self._Lmunu(short_nu, ga) + for ga in Partitions_n(nu.size()-nu[-1]) if mu.contains(ga) ) ) return self._self_to_m_cache[(mu,nu)] def _self_to_m(self, x): @@ -1569,9 +1595,9 @@ def _self_to_m(self, x): """ return self._m._from_dict({ part2: - self._base( sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) - for mu in x.homogeneous_component(d).support()) ) - for d in range(x.degree()+1) for part2 in Partitions(d) }) + self._base( sum(c * QQqt(self._Lmunu(part2, mu))(q=self.q, t=self.t) + for mu, c in x if self.degree_on_basis(mu) == d) ) + for d in range(x.degree()+1) for part2 in Partitions_n(d) }) def _m_to_self( self, f ): r""" @@ -1996,8 +2022,8 @@ def qt_kostka(lam, mu): sage: qt_kostka([2,1],[1,1,1,1]) 0 """ - lam = Partition(lam) - mu = Partition(mu) + lam = _Partitions(lam) + mu = _Partitions(mu) if lam.size() != mu.size(): return QQqt.zero() @@ -2010,7 +2036,7 @@ def qt_kostka(lam, mu): H = Sym.macdonald().H() s = Sym.schur() - parts = Partitions(mu.size()) + parts = Partitions_n(mu.size()) for p2 in parts: res = s(H(p2)) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 648200756ff..5aedd89e4a8 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -215,8 +215,7 @@ from sage.rings.all import Integer, PolynomialRing, QQ, ZZ from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.multi_polynomial import is_MPolynomial -import sage.combinat.partition -from sage.combinat.partition import _Partitions, Partitions +from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition import sage.libs.symmetrica.all as symmetrica # used in eval() from sage.combinat.free_module import CombinatorialFreeModule from sage.matrix.constructor import matrix @@ -308,8 +307,8 @@ def zee(part): sage: zee([2,1,1]) 4 """ - if not isinstance(part, sage.combinat.partition.Partition): - part = sage.combinat.partition.Partition(part) + if not isinstance(part, Partition): + part = _Partitions(part) return part.centralizer_size() @@ -593,7 +592,7 @@ def one_basis(self): .. TODO:: generalize to Modules.Graded.Connected.ParentMethods """ - return sage.combinat.partition.Partition([]) + return _Partitions([]) def degree_on_basis(self, b): r""" @@ -1883,7 +1882,7 @@ def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cach zero = base_ring.zero() #Get and store the list of partitions we'll need - pn = sage.combinat.partition.Partitions_n(n).list() + pn = Partitions_n(n).list() len_pn = len(pn) #Create the initial cache dictionaries @@ -2100,7 +2099,7 @@ def transition_matrix(self, basis, n): sage: e.transition_matrix(m,7) == e.transition_matrix(m,7).transpose() True """ - P = sage.combinat.partition.Partitions_n(n) + P = Partitions_n(n) Plist = P.list() m = [] for row_part in Plist: @@ -2167,7 +2166,7 @@ def _gram_schmidt(self, n, source, scalar, cache, leading_coeff=None, upper_tria # We are going to be doing everything like we are in the upper-triangular case # We list the partitions in "decreasing order" and work from the beginning forward. # If we are in the lower-triangular case, then we shouldn't reverse the list - l = Partitions(n).list() + l = Partitions_n(n).list() if upper_triangular: l.reverse() @@ -2257,7 +2256,7 @@ def _inner_plethysm_pk_g(self, k, g, cache): res = 0 degrees = uniq([ sum(m) for m in g.support() ]) for d in degrees: - for mu in sage.combinat.partition.Partitions(d): + for mu in Partitions_n(d): mu_k = mu.power(k) if mu_k in g: res += g.coefficient(mu_k)*mu_k.centralizer_size()/mu.centralizer_size()*p(mu) @@ -3019,7 +3018,7 @@ def theta(self,a): res = p_self.map_item(lambda m,c: (m, c * a**len(m))) return self.parent()(res) - def theta_qt(self,q=None,t=None): + def theta_qt(self, q=None, t=None): r""" Return the image of ``self`` under the `q,t`-deformed theta endomorphism which sends `p_k` to `\frac{1-q^k}{1-t^k} \cdot p_k` @@ -3066,10 +3065,16 @@ def theta_qt(self,q=None,t=None): q = parent.q else: q = BR(QQ['q'].gen()) - res = p_self.map_item(lambda m,c: (m, BR(prod([(1-q**k)/(1-t**k) for k in m])*c))) + one = BR.one() + if not t: + res = p._from_dict({m: BR(prod(one - q**k for k in m) * c) + for m,c in p_self}) + else: + res = p._from_dict({m: BR(prod((one-q**k) / (one-t**k) for k in m)*c) + for m,c in p_self}) return parent(res) - def omega_qt(self,q = None,t = None): + def omega_qt(self, q=None, t=None): r""" Return the image of ``self`` under the `q,t`-deformed omega automorphism which sends `p_k` to @@ -3134,8 +3139,16 @@ def omega_qt(self,q = None,t = None): q = parent.q else: q = BR(QQ['q'].gen()) - f = lambda part: prod([(-1)**(i-1)*(1-q**i)/(1-t**i) for i in part]) - res = p_self.map_item(lambda m,c: (m, BR(f(m)*c))) + one = BR.one() + if not t: + res = p._from_dict({m: c * (-one)**(sum(m)-len(m)) + * BR(prod(one-q**i for i in m)) + for m,c in p_self}) + else: + res = p._from_dict({m: c * (-one)**(sum(m)-len(m)) + * BR(prod((one-q**i) / (one-t**i) + for i in m)) + for m,c in p_self}) return parent(res) def itensor(self, x): From 0cb83533bfe821ae24dad1d95e7dc5d520fb1fdf Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 20:51:15 -0700 Subject: [PATCH 474/665] Fixing non-imports and a strange doctest failure. --- src/sage/combinat/sf/sfa.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 5aedd89e4a8..c5f08be3a97 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -245,7 +245,8 @@ def SymmetricFunctionAlgebra(R, basis="schur"): See http://trac.sagemath.org/15473 for details. Symmetric Functions over Rational Field in the Schur basis """ - sage.misc.superseded.deprecation(15473, "this function is deprecated. Use SymmetricFunctions(R).basis()") + from sage.misc.superseded import deprecation + deprecation(15473, "this function is deprecated. Use SymmetricFunctions(R).basis()") from sage.combinat.sf.sf import SymmetricFunctions Sym = SymmetricFunctions(R) if basis == 'schur' or basis == 's': @@ -1018,7 +1019,7 @@ def gessel_reutenauer(self, lam): ....: for sigma in Permutations(n) ....: if sigma.cycle_type() == lam]) ....: return r.to_symmetric_function() - sage: all( GR_def2(lam) == h.gessel_reutenauer(lam) + sage: all( h(GR_def2(lam)) == h.gessel_reutenauer(lam) ....: for n in range(5) for lam in Partitions(n) ) True @@ -1075,8 +1076,8 @@ def gessel_reutenauer(self, lam): m = lam.to_exp_dict() # == {i: m_i | i occurs in lam} p = self.realization_of().power() h = self.realization_of().complete() - mu = sage.rings.arith.Moebius() - from sage.rings.arith import squarefree_divisors + from sage.rings.arith import Moebius, squarefree_divisors + mu = Moebius() def component(i, g): # == h_g[L_i] L_i = p.sum_of_terms([(_Partitions([d] * (i//d)), R(mu(d))) for d in squarefree_divisors(i)], @@ -1304,7 +1305,7 @@ def carlitz_shareshian_wachs(self, n, d, s, comparison=None): # Stupid implementation. R = self.base_ring() m = self.realization_of().m() - Permus_mset = sage.combinat.permutation.Permutations_mset + from sage.combinat.permutation import Permutations_mset # Defining a ``check_word`` function. This function will be used # to check if an `n`-tuple `w` of positive integers belongs to # `W(n, d, s)` and satisfies the additional requirement @@ -1344,8 +1345,8 @@ def check_word(w): def coeff_of_m_mu_in_result(mu): # Compute the coefficient of the monomial symmetric # function ``m[mu]`` in the result. - words_to_check = Permus_mset([i for (i, l) in enumerate(mu) - for _ in range(l)]) + words_to_check = Permutations_mset([i for (i, l) in enumerate(mu) + for _ in range(l)]) return R( sum(1 for w in words_to_check if check_word(w)) ) from sage.combinat.partition import Partitions_n @@ -3772,7 +3773,8 @@ def left_padded_kronecker_product(self, x): sage: v = s[1].left_padded_kronecker_product(s[1]); parent(v) Symmetric Functions over Integer Ring in the Schur basis """ - _Compositions = sage.combinat.composition.Compositions() + from sage.combinat.composition import Compositions + _Compositions = Compositions() parent = self.parent() h = parent.realization_of().h() h_self = h(self) From 0a09d0f615166b8f65af971a61805663e81f3ff2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 22 Apr 2015 21:19:12 -0700 Subject: [PATCH 475/665] Fix for conversion from NCSF to Sym. --- src/sage/combinat/ncsf_qsym/qsym.py | 10 ++++++++-- src/sage/combinat/sf/sfa.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index d8a6c683e6e..40437ab13c2 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -2089,11 +2089,17 @@ def to_symmetric_function(self): m[] sage: (2*M([])).to_symmetric_function() 2*m[] + + We check that the result is indexed by partitions:: + + sage: M([]).to_symmetric_function().leading_support().parent() + Parittions """ m = SymmetricFunctions(self.parent().base_ring()).monomial() if self.is_symmetric(): - return m.sum_of_terms([(I, coeff) for (I, coeff) in self - if list(I) in _Partitions], distinct=True) + return m._from_dict({_Partitions(list(I)): coeff + for I, coeff in self + if list(I) in _Partitions}, remove_zeros=False) else: raise ValueError("%s is not a symmetric function"%self) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index c5f08be3a97..cd175ce76e6 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -1019,7 +1019,7 @@ def gessel_reutenauer(self, lam): ....: for sigma in Permutations(n) ....: if sigma.cycle_type() == lam]) ....: return r.to_symmetric_function() - sage: all( h(GR_def2(lam)) == h.gessel_reutenauer(lam) + sage: all( GR_def2(lam) == h.gessel_reutenauer(lam) ....: for n in range(5) for lam in Partitions(n) ) True From 0beb0422ac4482d67e670340ce7c26b2a927d916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 23 Apr 2015 08:39:41 +0200 Subject: [PATCH 476/665] trac #16352 more 'graded' in root_lattice_realizations.py --- src/sage/combinat/root_system/root_lattice_realizations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index fc6c5209902..a8e1fd36879 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -789,7 +789,7 @@ def positive_real_roots(self): """ if self.cartan_type().is_finite(): return tuple(RecursivelyEnumeratedSet(self.simple_roots(), - attrcall('pred'), structure=None, + attrcall('pred'), structure='graded', enumeration='breadth')) if not self.cartan_type().is_affine(): raise NotImplementedError("only implemented for finite and affine Cartan types") @@ -938,7 +938,7 @@ def parabolic_covers(alpha): generators = [x for x in self.simple_roots() if x.is_parabolic_root(index_set)] return RecursivelyEnumeratedSet(generators, parabolic_covers, - structure=None, enumeration='breadth') + structure='graded', enumeration='breadth') @cached_method def positive_roots_nonparabolic(self, index_set = None): From 001451251690a5245dc316b0d2f0cc1ede2b7b29 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 23 Apr 2015 10:03:56 +0200 Subject: [PATCH 477/665] trac #18283: Words random element is wrong --- src/sage/combinat/words/words.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index ebfb3e8048f..64c28f57b92 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -678,6 +678,8 @@ def _word_from_iter(self, data, length, caching=True): word: 1111111111 """ wc = '_with_caching' if caching else "" + if length is None: + length = getattr(self,'_length',None) if length in (None, Infinity, 'infinite'): return self._element_classes['InfiniteWord_iter'+wc](self, data, length) elif (length == 'finite') or (length in ZZ and length >= 0): From f515e4dadec76fe9897f8069ffa8599f7bb608a0 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 10:04:48 +0200 Subject: [PATCH 478/665] Removed __call__ = transmit --- src/sage/coding/channel_constructions.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 9933323d044..8f9eec9bf73 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -224,9 +224,7 @@ def __call__(self, message): sage: m1 == m2 True """ - pass - - __call__ = transmit + return self.transmit(message) def input_space(self): r""" From 87667eb0a98fdde70d4d915add36ea48abb6fc30 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 10:55:00 +0200 Subject: [PATCH 479/665] Removed sample_range method, propaged changes and changed code for transmit_unsafe in StaticErrorRateChannel --- src/sage/coding/channel_constructions.py | 21 +++++++------- src/sage/misc/prandom.py | 37 ------------------------ 2 files changed, 11 insertions(+), 47 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 8f9eec9bf73..aaeb655cb5c 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -26,11 +26,12 @@ from sage.structure.sage_object import SageObject from sage.rings.finite_rings.constructor import GF -from sage.misc.prandom import randint, random, sample_range +from sage.misc.prandom import randint, random, sample from sage.modules.free_module_element import vector from sage.misc.abstract_method import abstract_method from sage.combinat.cartesian_product import CartesianProduct from sage.modules.free_module import VectorSpace +from copy import copy def random_error_vector(n, F, error_positions): r""" @@ -412,12 +413,12 @@ def transmit_unsafe(self, message): sage: Chan.transmit_unsafe(msg) # random (4, 14, 15, 16, 17, 42) """ + w = copy(message) number_errors = tuple_to_integer(self.number_errors()) V = self.input_space() - n = V.dimension() - error_vector = random_error_vector(n, V.base_ring(),\ - sample_range(n, number_errors)) - return message + error_vector + for i in sample(xrange(V.dimension()), number_errors): + w[i] = V.base_ring().random_element() + return w def number_errors(self): r""" @@ -612,13 +613,13 @@ def transmit_unsafe(self, message): V = self.input_space() n = V.dimension() - erroneous_positions = sample_range(n,\ + erroneous_positions = sample(xrange(n),\ number_errors + number_erasures) - error_split = sample_range(number_errors + number_erasures,\ + error_split = sample(xrange(number_errors + number_erasures),\ number_errors) - error_positions = [ erroneous_positions[i] for i in\ - range(number_errors + number_erasures) if i in error_split ] - erasure_positions = [ erroneous_positions[i] for i in\ + error_positions = [erroneous_positions[i] for i in\ + range(number_errors + number_erasures) if i in error_split] + erasure_positions = [erroneous_positions[i] for i in\ range(number_errors + number_erasures) if i not in error_split] error_vector = random_error_vector(n, V.base_ring(), error_positions) diff --git a/src/sage/misc/prandom.py b/src/sage/misc/prandom.py index 115ddcb176a..95b26c78cdf 100644 --- a/src/sage/misc/prandom.py +++ b/src/sage/misc/prandom.py @@ -177,43 +177,6 @@ def sample(population, k): """ return _pyrand().sample(population, k) -def sample_range(n , k): - r""" - Returns a subset of [0, ..., n-1] of size k with uniform probability. - - INPUT: - - - ``n``, ``k`` -- integers - - OUTPUT: - - - An ordered list of integers - - AUTHORS: - - This function is taken from codinglib (https://bitbucket.org/jsrn/codinglib/) - and was written by Johan Nielsen. - - EXAMPLES:: - - sage: sample_range(6, 2) # random - [1, 4] - sage: set_random_seed(10) - sage: sample_range(10,4) - [6, 7, 8, 9] - """ - n = int(n) - k = int(k) - ordered_set = [] - i = 0 - while i < n and k > 0: - if random() < k/(n-i): - ordered_set.append(i) - k -= 1 - i += 1 - return ordered_set - - def random(): r""" Get the next random number in the range [0.0, 1.0). From f9b07be5c282cdf7fde03e522d6ee74c68a38487 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 11:33:04 +0200 Subject: [PATCH 480/665] Removed tuple_to_integer method --- src/sage/coding/channel_constructions.py | 114 +++++++++++------------ 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index aaeb655cb5c..a8f65209609 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -25,6 +25,7 @@ #***************************************************************************** from sage.structure.sage_object import SageObject +from sage.rings.integer import Integer from sage.rings.finite_rings.constructor import GF from sage.misc.prandom import randint, random, sample from sage.modules.free_module_element import vector @@ -69,38 +70,6 @@ def random_error_vector(n, F, error_positions): vect[i] = F._random_nonzero_element() return vector(F, vect) -def tuple_to_integer(value): - r""" - Returns an integer from ``value``. If ``value`` is a tuple, it will return a random - integer between its bounds. - - .. NOTE:: - - This is a helper function, which should only be used when implementing new channels. - - INPUT: - - - ``value`` -- an integer or a couple of integers - - OUTPUT: - - - an integer - - EXAMPLES:: - - sage: sage.coding.channel_constructions.tuple_to_integer(4) - 4 - - sage: sage.coding.channel_constructions.tuple_to_integer((1,5)) # random - 3 - """ - value = value if not hasattr(value, "__iter__") else randint(value[0], value[1]) - return value - - - - - class AbstractChannel(SageObject): r""" Abstract top-class for Channel objects. @@ -326,9 +295,12 @@ def __init__(self, space, number_errors): ... ValueError: There might be more errors than the dimension of the input space """ + if isinstance(number_errors, (Integer, int)): + number_errors = (number_errors, number_errors) + if not isinstance(number_errors, (tuple, list)): + raise ValueError("number_errors must be a tuple, a list, an Integer or a Python int") super(StaticErrorRateChannel, self).__init__(space, space) - no_err = number_errors if not hasattr(number_errors, "__iter__") else number_errors[1] - if no_err > space.dimension(): + if number_errors[1] > space.dimension(): raise ValueError("There might be more errors than the dimension of the input space") self._number_errors = number_errors @@ -344,11 +316,11 @@ def __repr__(self): sage: Chan Static error rate channel creating 42 error(s) """ - if not hasattr(self.number_errors(), "__iter__"): + no_err = self.number_errors() + if no_err[0] == no_err[1]: return "Static error rate channel creating %s error(s)"\ - % self.number_errors() + % no_err[0] else: - no_err = self.number_errors() return "Static error rate channel creating between %s and %s errors"\ % (no_err[0], no_err[1]) @@ -364,11 +336,11 @@ def _latex_(self): sage: Chan._latex_() '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' """ - if not hasattr(self.number_errors(), "__iter__"): + no_err = self.number_errors() + if no_err[0] == no_err[1]: return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ - % self.number_errors() + % no_err[0] else: - no_err = self.number_errors() return "\\textnormal{Static error rate channel, creating between %s and %s errors}"\ % (no_err[0], no_err[1]) @@ -414,7 +386,7 @@ def transmit_unsafe(self, message): (4, 14, 15, 16, 17, 42) """ w = copy(message) - number_errors = tuple_to_integer(self.number_errors()) + number_errors = randint(*self.number_errors()) V = self.input_space() for i in sample(xrange(V.dimension()), number_errors): w[i] = V.base_ring().random_element() @@ -430,7 +402,7 @@ def number_errors(self): sage: n_err = 3 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan.number_errors() - 3 + (3, 3) """ return self._number_errors @@ -500,13 +472,19 @@ def __init__(self, space, number_errors, number_erasures): ... ValueError: The total number of errors and erasures can exceed the dimension of the input space """ + if isinstance(number_errors, (Integer, int)): + number_errors = (number_errors, number_errors) + if not isinstance(number_errors, (tuple, list)): + raise ValueError("number_errors must be a tuple, a list, an Integer or a Python int") + + if isinstance(number_erasures, (Integer, int)): + number_erasures = (number_erasures, number_erasures) + if not isinstance(number_erasures, (tuple, list)): + raise ValueError("number_erasures must be a tuple, a list, an Integer or a Python int") + output_space = CartesianProduct(space, VectorSpace(GF(2), space.dimension())) super(ErrorErasureChannel, self).__init__(space, output_space) - no_err = number_errors if not hasattr(number_errors, "__iter__")\ - else number_errors[1] - no_era = number_erasures if not hasattr(number_erasures, "__iter__")\ - else number_erasures[1] - if no_err + no_era > space.dimension(): + if number_errors[1] + number_erasures[1] > space.dimension(): raise ValueError("The total number of errors and erasures can exceed the dimension of the input space") self._number_errors = number_errors self._number_erasures = number_erasures @@ -523,14 +501,20 @@ def __repr__(self): sage: Chan Error-and-erasure channel creating 21 error(s) and 21 erasure(s) """ - if not hasattr(self.number_errors(), "__iter__"): + no_err = self.number_errors() + no_era = self.number_erasures() + if no_err[0] == no_err[1] and no_era[0] == no_era[1]: return "Error-and-erasure channel creating %s error(s) and %s erasure(s)"\ - %(self.number_errors(), self.number_erasures()) + %(no_err[0], no_era[0]) + elif no_err[0] != no_err[1] and no_era[0] == no_era[1]: + return "Error-and-erasure channel creating between %s and %s errors and %s erasure(s)"\ + % (no_err[0], no_err[1], no_era[0]) + elif no_err[0] == no_err[1] and no_era[0] != no_era[1]: + return "Error-and-erasure channel creating %s error(s) and between %s and %s erasures"\ + % (no_err[0], no_era[0], no_era[1]) else: - no_err = self.number_errors() - no_era = self.number_erasures() return "Error-and-erasure channel creating between %s and %s errors and between %s and %s erasures"\ - % (no_err[0], no_err[1], no_era[0], no_era[1]) + % (no_err[0], no_err[1], no_era[0], no_era[1]) def _latex_(self): r""" @@ -544,14 +528,20 @@ def _latex_(self): sage: latex(Chan) \textnormal{Error-and-erasure channel creating 21 error(s) and 21 erasure(s)} """ - if not hasattr(self.number_errors(), "__iter__"): + no_err = self.number_errors() + no_era = self.number_erasures() + if no_err[0] == no_err[1] and no_era[0] == no_era[1]: return "\\textnormal{Error-and-erasure channel creating %s error(s) and %s erasure(s)}"\ - %(self.number_errors(), self.number_erasures()) + %(no_err[0], no_era[0]) + elif no_err[0] != no_err[1] and no_era[0] == no_era[1]: + return "\\textnormal{Error-and-erasure channel creating between %s and %s error(s) and %s erasure(s)}"\ + % (no_err[0], no_err[1], no_era[0]) + elif no_err[0] == no_err[1] and no_era[0] != no_era[1]: + return "\\textnormal{Error-and-erasure channel creating %s error(s) and between %s and %s erasure(s)}"\ + % (no_err[0], no_era[0], no_era[1]) else: - no_err = self.number_errors() - no_era = self.number_erasures() - return "\\textnormal{Error-and-erasure channel creating between %s and %s errors and between %s and %s erasures}"\ - % (no_err[0], no_err[1], no_era[0], no_era[1]) + return "\\textnormal{Error-and-erasure channel creating between %s and %s error(s) and between %s and %s erasure(s)}"\ + % (no_err[0], no_err[1], no_era[0], no_era[1]) def __eq__(self, other): r""" @@ -608,8 +598,8 @@ def transmit_unsafe(self, message): sage: Chan.transmit_unsafe(msg) # random ((0, 14, 15, 0, 26, 53, 45, 9, 7, 14, 3), (1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) """ - number_errors = tuple_to_integer(self.number_errors()) - number_erasures = tuple_to_integer(self.number_erasures()) + number_errors = randint(*self.number_errors()) + number_erasures = randint(*self.number_erasures()) V = self.input_space() n = V.dimension() @@ -641,7 +631,7 @@ def number_errors(self): sage: n_err, n_era = 3, 0 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: Chan.number_errors() - 3 + (3, 3) """ return self._number_errors @@ -655,6 +645,6 @@ def number_erasures(self): sage: n_err, n_era = 0, 3 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: Chan.number_erasures() - 3 + (3, 3) """ return self._number_erasures From 76084b7502c0173da54ef15fb1dbe7f31162a066 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 23 Apr 2015 12:39:12 +0200 Subject: [PATCH 481/665] make X readable --- src/sage/combinat/species/generating_series.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 01e3dd90701..7e2e93fe8ff 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -302,7 +302,7 @@ def CycleIndexSeriesRing(R): r""" Return the ring of cycle index series over ``R``. - This is the ring of formal power series `\Lambda[X]`, where + This is the ring of formal power series `\Lambda[x]`, where `\Lambda` is the ring of symmetric functions over ``R`` in the `p`-basis. Its purpose is to house the cycle index series of species (in a somewhat nonstandard notation tailored to Sage): @@ -314,16 +314,16 @@ def CycleIndexSeriesRing(R): \sum_{n \geq 0} \frac{1}{n!} (\sum_{\sigma \in S_n} \operatorname{fix} F[\sigma] \prod_{z \text{ is a cycle of } \sigma} - p_{\text{length of } z}) X^n - \in \Lambda_\QQ [X], + p_{\text{length of } z}) x^n + \in \Lambda_\QQ [x], where `\operatorname{fix} F[\sigma]` denotes the number of fixed points of the permutation `F[\sigma]` of `F[n]`. We notice that this power series is "equigraded" (meaning that - its `X^n`-coefficient is homogeneous of degree `n`). A more + its `x^n`-coefficient is homogeneous of degree `n`). A more standard convention in combinatorics would be to use - `x_i` instead of `p_i`, and drop the `X` (that is, evaluate - the above power series at `X = 1`); but this would be more + `x_i` instead of `p_i`, and drop the `x` (that is, evaluate + the above power series at `x = 1`); but this would be more difficult to implement in Sage, as it would be an element of a power series ring in infinitely many variables. From dc770406c96a27d7925a149f01bdc4e88123392b Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 23 Apr 2015 13:11:08 +0200 Subject: [PATCH 482/665] Trac 18076: review commit - fix doctest - simplify + type check in NumpyToSRMorphism - use RR instead of RDF for conversion numpy -> QQ - rearrange RDF._coerce_map_from_ --- src/sage/rings/complex_double.pyx | 6 +++--- src/sage/rings/rational.pyx | 2 +- src/sage/rings/real_double.pyx | 14 +++++++++++--- src/sage/structure/coerce.pyx | 8 ++++---- src/sage/symbolic/ring.pyx | 23 ++++++++++++++++------- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index ebd4973d4ca..ad9bfa7dbdd 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -2505,9 +2505,9 @@ cdef class ComplexToCDF(Morphism): sage: import numpy sage: f = CDF.coerce_map_from(numpy.complex_) - sage: f(numpy.complex_(1jr)) + sage: f(numpy.complex_(I)) 1.0*I - sage: f(numpy.complex_(1jr)).parent() + sage: f(numpy.complex_(I)).parent() Complex Double Field """ def __init__(self, R): @@ -2524,7 +2524,7 @@ cdef class ComplexToCDF(Morphism): EXAMPLES:: sage: import numpy - sage: CDF(numpy.complex_(1jr)) # indirect doctest + sage: CDF(numpy.complex_(I)) # indirect doctest 1.0*I """ cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index fe70c7c6f09..5072f49d729 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -563,7 +563,7 @@ cdef class Rational(sage.structure.element.FieldElement): if isinstance(x, numpy.integer): self.__set_value(integer.Integer(x), base) elif isinstance(x, numpy.floating): - self.__set_value(sage.rings.real_double.RDF(x), base) + self.__set_value(sage.rings.real_mpfr.RR(x), base) else: raise TypeError("Unable to coerce {} ({}) to Rational".format(x,type(x))) diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index a2c3413d8ff..87c7f2d2e32 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -322,7 +322,7 @@ cdef class RealDoubleField_class(Field): ... TypeError: no canonical coercion from Symbolic Ring to Real Double Field - Test that :trac:`15965` is fixed (see also :trac:`18076`):: + Test that :trac:`15695` is fixed (see also :trac:`18076`):: sage: 1j + numpy.float64(2) 2.00000000000000 + 1.00000000000000*I @@ -331,17 +331,25 @@ cdef class RealDoubleField_class(Field): """ if S is int or S is float: return ToRDF(S) + from rational_field import QQ from real_lazy import RLF - from real_mpfr import RR, RealField_class - if S is ZZ or S is QQ or S is RLF or (isinstance(S, RealField_class) and S.prec() >= 53): + if S is ZZ or S is QQ or S is RLF: return ToRDF(S) + + from real_mpfr import RR, RealField_class + if isinstance(S, RealField_class): + if S.prec() >= 53: + return ToRDF(S) + else: + return None elif is_numpy_type(S): import numpy if issubclass(S, numpy.integer) or issubclass(S, numpy.floating): return ToRDF(S) else: return None + connecting = RR._internal_coerce_map_from(S) if connecting is not None: return ToRDF(RR) * connecting diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index fe8ec25204f..8262f710097 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -135,7 +135,7 @@ cpdef py_scalar_parent(py_type): sage: py_scalar_parent(numpy.complex) Complex Double Field """ - if issubclass(py_type, int) or issubclass(py_type, long) or issubclass(py_type, bool): + if issubclass(py_type, int) or issubclass(py_type, long): import sage.rings.integer_ring return sage.rings.integer_ring.ZZ elif issubclass(py_type, float): @@ -206,8 +206,8 @@ cpdef py_scalar_to_element(x): ....: numpy.int32('-19'), numpy.uint32('44'), ....: numpy.int64('-3'), numpy.uint64('552'), ....: numpy.float16('-1.23'), numpy.float32('-2.22'), - ....: numpy.float64('-3.412'), numpy.complex64(1.2+1jr), - ....: numpy.complex128(-2+.1jr)] + ....: numpy.float64('-3.412'), numpy.complex64(1.2+I), + ....: numpy.complex128(-2+.I)] sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() """ @@ -1124,7 +1124,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): if x_numeric and y_numeric: ty = type(x + y) if ty != type(y + x): - raise RuntimeError("x + y and y + x have different types for x={} ({}) and y={} ({})".format(x, type(x), y, type(y))) + raise TypeError("x + y and y + x have different types for x={} (of type {}) and y={} (of type {})".format(x, type(x), y, type(y))) return ty(x), ty(y) # Now handle the native python + sage object cases diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 83841c22b72..43653e3d53d 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -142,7 +142,7 @@ cdef class SymbolicRing(CommutativeRing): if (issubclass(R, numpy.integer) or issubclass(R, numpy.floating) or issubclass(R, numpy.complexfloating)): - return NumpyToSRMorphism(R, self) + return NumpyToSRMorphism(R) else: return None @@ -823,35 +823,44 @@ cdef class NumpyToSRMorphism(Morphism): """ cdef _intermediate_ring - def __init__(self, numpy_type, R): + def __init__(self, numpy_type): """ A Morphism which constructs Expressions from NumPy floats and complexes by converting them to elements of either RDF or CDF. + INPUT: + + - ``numpy_type`` - a numpy number type + EXAMPLES:: sage: import numpy sage: from sage.symbolic.ring import NumpyToSRMorphism - sage: f = NumpyToSRMorphism(numpy.float64, SR) + sage: f = NumpyToSRMorphism(numpy.float64) sage: f(numpy.float64('2.0')) 2.0 sage: _.parent() Symbolic Ring + + sage: NumpyToSRMorphism(str) + Traceback (most recent call last): + ... + TypeError: is not a numpy number type """ - import sage.categories.homset - from sage.structure.parent import Set_PythonType - Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(numpy_type), R)) + Morphism.__init__(self, numpy_type, SR) import numpy if issubclass(numpy_type, numpy.integer): from sage.rings.all import ZZ self._intermediate_ring = ZZ - if issubclass(numpy_type, numpy.floating): + elif issubclass(numpy_type, numpy.floating): from sage.rings.all import RDF self._intermediate_ring = RDF elif issubclass(numpy_type, numpy.complexfloating): from sage.rings.all import CDF self._intermediate_ring = CDF + else: + raise TypeError("{} is not a numpy number type".format(numpy_type)) cpdef Element _call_(self, a): """ From ccaf80c11d5ad4cc7207f7d03d42a947a72aa9c7 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Thu, 23 Apr 2015 13:51:03 +0200 Subject: [PATCH 483/665] Trac 18076: more fixes in structure.coerce --- src/sage/structure/coerce.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 8262f710097..bfe2ac2eb7f 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -207,7 +207,7 @@ cpdef py_scalar_to_element(x): ....: numpy.int64('-3'), numpy.uint64('552'), ....: numpy.float16('-1.23'), numpy.float32('-2.22'), ....: numpy.float64('-3.412'), numpy.complex64(1.2+I), - ....: numpy.complex128(-2+.I)] + ....: numpy.complex128(-2+I)] sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() """ @@ -1123,8 +1123,6 @@ cdef class CoercionModel_cache_maps(CoercionModel): if x_numeric and y_numeric: ty = type(x + y) - if ty != type(y + x): - raise TypeError("x + y and y + x have different types for x={} (of type {}) and y={} (of type {})".format(x, type(x), y, type(y))) return ty(x), ty(y) # Now handle the native python + sage object cases From f93852e00d00dd694bed6c068d87cd17ad1a5d3c Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 13:57:05 +0200 Subject: [PATCH 484/665] Improved documentation --- src/sage/coding/channel_constructions.py | 57 ++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index a8f65209609..4ac00e7f3a4 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -7,10 +7,10 @@ This file contains the following elements: - - *AbstractChannel*, the abstract class for Channels - - *StaticErrorRateChannel*, which creates a specific number of errors in each + - :class:`AbstractChannel`, the abstract class for Channels + - :class:`StaticErrorRateChannel`, which creates a specific number of errors in each transmitted message - - *ErrorErasureChannel*, which creates a specific number of errors and a + - :class:`ErrorErasureChannel`, which creates a specific number of errors and a specific number of erasures in each transmitted message """ @@ -151,8 +151,9 @@ def transmit(self, message): sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) - sage: Chan.transmit(msg) # random - (4, 14, 15, 16, 17, 42) + sage: set_random_seed(10) + sage: Chan.transmit(msg) + (4, 8, 4, 16, 23, 53) If we transmit a vector which is not in the input space of ``self``:: @@ -252,6 +253,24 @@ class StaticErrorRateChannel(AbstractChannel): it transmits. The input space and the output space of this channel are the same. + The main purpose of communication channels is to transmit messages, which can be achieved with + two methods: + + - with the method :meth:`AbstractChannel.transmit`. Considering a channel ``Chan`` + and a message ``msg``, transmitting + ``msg`` with ``Chan`` can be done this way:: + + Chan.transmit(msg) + + It can also be written in a more convenient way:: + + Chan(msg) + + - with the method :meth:`transmit_unsafe`. It does the exact same thing as :meth:`transmit` except + that it does not check if ``msg`` belongs to the input space of ``Chan``:: + + Chan.transmit_unsafe(msg) + INPUT: - ``space`` -- the space of both input and output @@ -382,8 +401,9 @@ def transmit_unsafe(self, message): sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) - sage: Chan.transmit_unsafe(msg) # random - (4, 14, 15, 16, 17, 42) + sage: set_random_seed(10) + sage: Chan.transmit_unsafe(msg) + (4, 8, 4, 16, 23, 53) """ w = copy(message) number_errors = randint(*self.number_errors()) @@ -421,6 +441,24 @@ class ErrorErasureChannel(AbstractChannel): in the transmitted message. The output space of this channel is a cartesian product between its input space and a VectorSpace of the same dimension over GF(2) + The main purpose of communication channels is to transmit messages, which can be achieved with + two methods: + + - with the method :meth:`AbstractChannel.transmit`. Considering a channel ``Chan`` + and a message ``msg``, transmitting + ``msg`` with ``Chan`` can be done this way:: + + Chan.transmit(msg) + + It can also be written in a more convenient way:: + + Chan(msg) + + - with the method :meth:`transmit_unsafe`. It does the exact same thing as :meth:`transmit` except + that it does not check if ``msg`` belongs to the input space of ``Chan``:: + + Chan.transmit_unsafe(msg) + INPUT: - ``space`` -- the input and output space @@ -595,8 +633,9 @@ def transmit_unsafe(self, message): sage: n_err, n_era = 2, 2 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3)) - sage: Chan.transmit_unsafe(msg) # random - ((0, 14, 15, 0, 26, 53, 45, 9, 7, 14, 3), (1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) + sage: set_random_seed(10) + sage: Chan.transmit_unsafe(msg) + ((32, 0, 15, 9, 8, 53, 58, 9, 0, 9, 3), (0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0)) """ number_errors = randint(*self.number_errors()) number_erasures = randint(*self.number_erasures()) From 58a7ca76ff2a99d02fd7d5b40a6cd389bfd4fca5 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 23 Apr 2015 14:19:18 +0200 Subject: [PATCH 485/665] Fix coverage formatting --- src/bin/sage-coverageall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/sage-coverageall b/src/bin/sage-coverageall index 82ab31a96dc..6cd8ae22cdd 100755 --- a/src/bin/sage-coverageall +++ b/src/bin/sage-coverageall @@ -30,7 +30,7 @@ def coverage_all(directory): if total != 0: score = (float(scr) / total) - print("Overall weighted coverage score: {:.1%}".format(score)) + print("Overall weighted coverage score: {:.1f}%".format(score)) print("Total number of functions: {}".format(total)) # Print up to 3 doctest coverage goals. From 5ce7e9c80f2886161816f526fb3574f3c75712b8 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 23 Apr 2015 10:55:24 -0400 Subject: [PATCH 486/665] delete Bmu since it is no longer used, plus two minor changes shave seconds off previous test --- src/sage/combinat/sf/macdonald.py | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index b4ffbf973f2..ec9c91c970c 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -608,33 +608,6 @@ def c2(part, q, t): res *= 1-q**(sum(part.arm_lengths(),[])[i])*t**(sum(part.leg_lengths(),[])[i]+1) return res -@cached_function -def Bmu(mu): - r""" - Return the bi-exponent generator for the cells of ``mu``. - - The weight in the bi-exponent generator is `t` raised the - `x`-coordinate of the cell, `q` raised to the `y` coordinate. - - INPUT: - - - ``mu`` -- a partition or a skew partition - - OUTPUT: - - - a polynomial in `q` and `t` - - EXAMPLES:: - - sage: from sage.combinat.sf.macdonald import Bmu - sage: Bmu(Partition([2,1])) - q + t + 1 - sage: Bmu(SkewPartition([[3,3],[2]])) - q^2*t + q^2 + q*t + t - """ - q,t = QQqt.gens() - return QQqt.sum(t**c[0] * q**c[1] for c in mu.cells()) - @cached_function def cmunu1(mu, nu): r""" @@ -1562,7 +1535,7 @@ def _Lmunu(self, nu, mu): for ga in mu.down()) ) else: self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu(mu,ga) * self._Lmunu(short_nu, ga) - for ga in Partitions_n(nu.size()-nu[-1]) if mu.contains(ga) ) ) + for ga in Partitions_n(short_nu.size()) if mu.contains(ga) ) ) return self._self_to_m_cache[(mu,nu)] def _self_to_m(self, x): @@ -1596,7 +1569,7 @@ def _self_to_m(self, x): """ return self._m._from_dict({ part2: self._base( sum(c * QQqt(self._Lmunu(part2, mu))(q=self.q, t=self.t) - for mu, c in x if self.degree_on_basis(mu) == d) ) + for mu, c in x if sum(mu)==d) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) def _m_to_self( self, f ): From bf02606324a12c4749f69f8139e9c3bd9d902e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 23 Apr 2015 17:09:24 +0200 Subject: [PATCH 487/665] 16659: is_identity_decomposition_into_orthogonal_idempotents + documentation + implement Monoids.Algebras.algebra_generators from monoid_generators --- src/sage/categories/examples/monoids.py | 18 +++++ .../finite_dimensional_algebras_with_basis.py | 65 ++++++++++++------- src/sage/categories/monoids.py | 46 +++++++++++++ src/sage/categories/semigroups.py | 8 ++- 4 files changed, 112 insertions(+), 25 deletions(-) diff --git a/src/sage/categories/examples/monoids.py b/src/sage/categories/examples/monoids.py index 3b8f057f0c3..da9971590e6 100644 --- a/src/sage/categories/examples/monoids.py +++ b/src/sage/categories/examples/monoids.py @@ -13,6 +13,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.categories.all import Monoids from semigroups import FreeSemigroup +from sage.sets.family import Family class FreeMonoid(FreeSemigroup): r""" @@ -116,6 +117,23 @@ def one(self): """ return self("") + @cached_method + def monoid_generators(self): + r""" + Return the generators of this monoid. + + EXAMPLES:: + + sage: M = Monoids().example(); M + An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd') + sage: M.monoid_generators() + Finite family {'a': 'a', 'c': 'c', 'b': 'b', 'd': 'd'} + sage: a,b,c,d = M.monoid_generators() + sage: a*d*c*b + 'adcb' + """ + return Family(self.alphabet, self) + class Element (ElementWrapper): wrapped_class = str diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index cff925a8d47..0889693145f 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -16,6 +16,7 @@ # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011-2015 Nicolas M. Thiéry # 2011-2015 Franco Saliola +# 2014-2015 Aladin Virmaux # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ @@ -850,55 +851,73 @@ def peirce_decomposition(self, idempotents=None, check=True): .. TODO:: - - Extract a method that tests whether a collection of - elements form a decomposition of the identity into - orthogonal idempotents. - - Specify the order in which the summands are returned, or return a list of list or a dictionary. """ if idempotents is None: idempotents = self.orthogonal_idempotents_central_mod_rad() if check: - if not self.is_orthogonal_idempotents(idempotents): - raise ValueError("Not a collection of orthogonal idempotents that sum to 1") + if not self.is_identity_decomposition_into_orthogonal_idempotents(idempotents): + raise ValueError("Not a decomposition of the identity into orthogonal idempotents") return [self.peirce_summand(ei, ej) for ei in idempotents for ej in idempotents] - def is_orthogonal_idempotents(self, l): + def is_identity_decomposition_into_orthogonal_idempotents(self, l): r""" - Return True of ``l`` is a list of orthogonal idempotents with sum - one. + Return whether ``l`` is a decomposition of the identity + into orthogonal idempotents. INPUT: - - ``l`` -- a list of elements of ``self`` + - ``l`` -- a list or iterable of elements of ``self`` - OUTPUT: + EXAMPLES:: - - True if ``l`` is a list of orthogonal idempotents with sum `1`, - False otherwise. + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field - EXAMPLES:: + sage: x,y,a,b = A.algebra_generators(); x,y,a,b + (x, y, a, b) - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example() - sage: A.is_orthogonal_idempotents(A.orthogonal_idempotents_central_mod_rad()) + sage: A.is_identity_decomposition_into_orthogonal_idempotents([A.one()]) True + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x,y]) + True + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x+a, y-a]) + True + + Here the idempotents do not sum up to `1`:: + + sage: A.is_identity_decomposition_into_orthogonal_idempotents([x]) + False + + Here `1+x` and `-x` are neither idempotent nor orthogonal:: + + sage: A.is_identity_decomposition_into_orthogonal_idempotents([1+x,-x]) + False With the algebra of the `0`-Hecke monoid:: - sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup - sage: W = WeylGroup(['A', 4]); W.rename("W") + sage: W = SymmetricGroup(4); W.rename("W") sage: ambient_monoid = FiniteSetMaps(W, action="right") sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: A = AutomaticSemigroup(pi, one=ambient_monoid.one()).algebra(QQ) - sage: A.is_orthogonal_idempotents(A.orthogonal_idempotents_central_mod_rad()) + sage: A = ambient_monoid.submonoid(pi).algebra(QQ) + sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True + + .. TODO:: + + Add examples of elements that are orthogonal and sum + to the identity yet are not idempotent and reciprocally. + """ - return (self.sum(l) == self.one() and all(e*e == e for e in l) - and all(e*f == 0 and f*e == 0 for e in l for f in l if f != e) - and sum(l) == self.one()) + return (self.sum(l) == self.one() + and all(e*e == e for e in l) + and all(e*f == 0 for e in l for f in l if f != e)) class ElementMethods: diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 152e8cf3603..19359a7b2e9 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -457,6 +457,52 @@ def one_basis(self): """ return self.basis().keys().one() + @cached_method + def algebra_generators(self): + r""" + Return generators for this algebra. + + For a monoid algebra, the algebra generators are built + from the monoid generators if available and from the + semigroup generators otherwise. + + .. SEEALSO:: + + - :meth:`Semigroups.Algebras.ParentMethods.algebra_generators` + - :meth:`MagmaticAlgebras.ParentMethods.algebra_generators() + <.magmatic_algebras.MagmaticAlgebras.ParentMethods.algebra_generators>`. + + EXAMPLES:: + + sage: M = Monoids().example(); M + An example of a monoid: + the free monoid generated by ('a', 'b', 'c', 'd') + sage: M.monoid_generators() + Finite family {'a': 'a', 'c': 'c', 'b': 'b', 'd': 'd'} + sage: M.algebra(ZZ).algebra_generators() + Finite family {'a': B['a'], 'c': B['c'], 'b': B['b'], 'd': B['d']} + + sage: Z12 = Monoids().Finite().example(); Z12 + An example of a finite multiplicative monoid: + the integers modulo 12 + sage: Z12.monoid_generators() + Traceback (most recent call last): + ... + AttributeError: 'IntegerModMonoid_with_category' object + has no attribute 'monoid_generators' + sage: Z12.semigroup_generators() + Family (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) + sage: Z12.algebra(QQ).algebra_generators() + Finite family {0: B[0], 1: B[1], 2: B[2], 3: B[3], 4: B[4], 5: B[5], + 6: B[6], 7: B[7], 8: B[8], 9: B[9], 10: B[10], 11: B[11]} + """ + monoid = self.basis().keys() + try: + generators = monoid.monoid_generators() + except AttributeError: + generators = monoid.semigroup_generators() + return generators.map(self.monomial) + class ElementMethods: def is_central(self): diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 17a5e17bd4b..747fa9e07da 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -593,8 +593,12 @@ def algebra_generators(self): EXAMPLES:: - sage: A = FiniteSemigroups().example().algebra(ZZ) - sage: A.algebra_generators() + sage: M = FiniteSemigroups().example(); M + An example of a finite semigroup: + the left regular band generated by ('a', 'b', 'c', 'd') + sage: M.semigroup_generators() + Family ('a', 'b', 'c', 'd') + sage: M.algebra(ZZ).algebra_generators() Finite family {0: B['a'], 1: B['b'], 2: B['c'], 3: B['d']} """ return self.basis().keys().semigroup_generators().map(self.monomial) From 7479f9fd1a706db78d59eb072ccc0c8db7fae936 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 17:19:01 +0200 Subject: [PATCH 488/665] Renamed AbstractChannel as Channel, removed __call__ as a defined method to avoid duplication in the documentation --- src/sage/coding/channel_constructions.py | 36 ++++++------------------ 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 4ac00e7f3a4..64f740ab096 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -7,7 +7,7 @@ This file contains the following elements: - - :class:`AbstractChannel`, the abstract class for Channels + - :class:`Channel`, the abstract class for Channels - :class:`StaticErrorRateChannel`, which creates a specific number of errors in each transmitted message - :class:`ErrorErasureChannel`, which creates a specific number of errors and a @@ -70,7 +70,7 @@ def random_error_vector(n, F, error_positions): vect[i] = F._random_nonzero_element() return vector(F, vect) -class AbstractChannel(SageObject): +class Channel(SageObject): r""" Abstract top-class for Channel objects. @@ -111,7 +111,7 @@ def __init__(self, input_space, output_space): We first create a new Channel subclass:: - sage: class ChannelExample(sage.coding.channel_constructions.AbstractChannel): + sage: class ChannelExample(sage.coding.channel_constructions.Channel): ....: def __init__(self, input_space, output_space): ....: super(ChannelExample, self).__init__(input_space, output_space) @@ -175,27 +175,7 @@ def transmit(self, message): else : raise TypeError("Message must be an element of the input space for the given channel") - def __call__(self, message): - r""" - This is an alias for ``transmit`` method. - With this method, one can transmit a message ``msg`` through a Channel ``Chan`` - by calling ``Chan(msg)`` instead of having to write ``Chan.transmit(msg)``. - See :meth:`transmit` for details. - - EXAMPLES:: - - sage: F = VectorSpace(GF(59), 6) - sage: n_err = 2 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) - sage: msg = F((4, 8, 15, 16, 23, 42)) - sage: set_random_seed(10) - sage: m1 = Chan(msg) - sage: set_random_seed(10) - sage: m2 = Chan.transmit(msg) - sage: m1 == m2 - True - """ - return self.transmit(message) + __call__ = transmit def input_space(self): r""" @@ -247,7 +227,7 @@ def transmit_unsafe(self, message): -class StaticErrorRateChannel(AbstractChannel): +class StaticErrorRateChannel(Channel): r""" Constructs a channel which adds a static number of errors to each message it transmits. The input space and the output space of this channel @@ -256,7 +236,7 @@ class StaticErrorRateChannel(AbstractChannel): The main purpose of communication channels is to transmit messages, which can be achieved with two methods: - - with the method :meth:`AbstractChannel.transmit`. Considering a channel ``Chan`` + - with the method :meth:`Channel.transmit`. Considering a channel ``Chan`` and a message ``msg``, transmitting ``msg`` with ``Chan`` can be done this way:: @@ -435,7 +415,7 @@ def number_errors(self): -class ErrorErasureChannel(AbstractChannel): +class ErrorErasureChannel(Channel): r""" Constructs a channel which adds errors to any message it transmits. It also erases several positions in the transmitted message. The output space of this channel is a cartesian product @@ -444,7 +424,7 @@ class ErrorErasureChannel(AbstractChannel): The main purpose of communication channels is to transmit messages, which can be achieved with two methods: - - with the method :meth:`AbstractChannel.transmit`. Considering a channel ``Chan`` + - with the method :meth:`Channel.transmit`. Considering a channel ``Chan`` and a message ``msg``, transmitting ``msg`` with ``Chan`` can be done this way:: From 2bc05906eb2db277bac427ec2ea55a47f95f1f26 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Thu, 23 Apr 2015 17:35:48 +0200 Subject: [PATCH 489/665] Small changes to documentation. Removed __eq__ methods --- src/sage/coding/channel_constructions.py | 44 +++--------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 64f740ab096..becf2a85247 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -84,7 +84,7 @@ class Channel(SageObject): - override :meth:`transmit_unsafe`. While not being mandatory, it might be useful to reimplement representation methods (``__repr__`` and - ``_latex_``), along with a comparison method (``__eq__``). + ``_latex_``). This abstract class provides the following parameters: @@ -175,6 +175,7 @@ def transmit(self, message): else : raise TypeError("Message must be an element of the input space for the given channel") + #Alias for transmit method __call__ = transmit def input_space(self): @@ -216,7 +217,6 @@ def transmit_unsafe(self, message): This is an abstract method which should be reimplemented in all the subclasses of Channel. """ - raise NotImplementedError @@ -343,23 +343,6 @@ def _latex_(self): return "\\textnormal{Static error rate channel, creating between %s and %s errors}"\ % (no_err[0], no_err[1]) - def __eq__(self, other): - r""" - Checks if ``self`` is equal to ``other``. - - EXAMPLES:: - - sage: F = VectorSpace(GF(59), 50) - sage: n_err = 42 - sage: Chan1 = channels.StaticErrorRateChannel(F, n_err) - sage: Chan2 = channels.StaticErrorRateChannel(F, n_err) - sage: Chan1 == Chan2 - True - """ - return isinstance(other, StaticErrorRateChannel)\ - and self.input_space() == other.input_space()\ - and self.number_errors() == other.number_errors() - def transmit_unsafe(self, message): r""" Returns ``message`` with as many errors as ``self._number_errors`` in it. @@ -488,7 +471,7 @@ def __init__(self, space, number_errors, number_erasures): sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) Traceback (most recent call last): ... - ValueError: The total number of errors and erasures can exceed the dimension of the input space + ValueError: The total number of errors and erasures can not exceed the dimension of the input space """ if isinstance(number_errors, (Integer, int)): number_errors = (number_errors, number_errors) @@ -503,7 +486,7 @@ def __init__(self, space, number_errors, number_erasures): output_space = CartesianProduct(space, VectorSpace(GF(2), space.dimension())) super(ErrorErasureChannel, self).__init__(space, output_space) if number_errors[1] + number_erasures[1] > space.dimension(): - raise ValueError("The total number of errors and erasures can exceed the dimension of the input space") + raise ValueError("The total number of errors and erasures can not exceed the dimension of the input space") self._number_errors = number_errors self._number_erasures = number_erasures @@ -561,25 +544,6 @@ def _latex_(self): return "\\textnormal{Error-and-erasure channel creating between %s and %s error(s) and between %s and %s erasure(s)}"\ % (no_err[0], no_err[1], no_era[0], no_era[1]) - def __eq__(self, other): - r""" - Checks if ``self`` is equal to ``other``. - - EXAMPLES:: - - sage: F = VectorSpace(GF(59), 50) - sage: n_err = 17 - sage: n_era = 7 - sage: Chan1 = channels.ErrorErasureChannel(F, n_err, n_era) - sage: Chan2 = channels.ErrorErasureChannel(F, n_err, n_era) - sage: Chan1 == Chan2 - True - """ - return isinstance(other, ErrorErasureChannel)\ - and self.input_space() == other.input_space()\ - and self.number_errors() == other.number_errors()\ - and self.number_erasures() == other.number_erasures() - def transmit_unsafe(self, message): r""" Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures From a62fdea2dd552075e22c39dc94fe7a3fa110d538 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 23 Apr 2015 11:46:12 -0400 Subject: [PATCH 490/665] 18271 enhancement add Stanley's hook formula The cardinality function for SemistandardTableaux_shape now uses the hook formula instead of summing over the weights. --- src/sage/combinat/tableau.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index c47fd74103e..face0553c2c 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5349,9 +5349,19 @@ def _repr_(self): return "Semistandard tableaux of shape %s and maximum entry %s" %(str(self.shape), str(self.max_entry)) def cardinality(self): - """ + r""" Returns the cardinality of ``self``. + This is computed using *Stanley's hook length formula* + + .. MATH:: + f_{\lambda} = \prod_{u\in\lambda} \frac{n+c(u)}{h(u)}. + + where `n` is the ``max_entry``, `c(u)` is the content of `u` and `h(u)` is the hook length + of `u`. + + See [Sta99] Corallary 7.21.4. + EXAMPLES:: sage: SemistandardTableaux([2,1]).cardinality() @@ -5364,14 +5374,28 @@ def cardinality(self): 126 sage: SemistandardTableaux([3,2,1]).cardinality() 896 - sage: SemistandardTableaux([3,2,1], max_entry=7).cardinality() 2352 + sage: SemistandardTableaux([6,5,4,3,2,1], max_entry=30).cardinality() + 208361017592001331200 + + + REFERENCES: + + .. [Sta99] Stanley, Richard. + Enumerative Combinatorics, Vol. 2. + Cambridge University Press, 1999 + """ - from sage.combinat.partition import Partitions - number = prod((self.max_entry + self.shape.content(*c)) / self.shape.hook_length(*c) - for c in self.shape.cells()) - return Integer(number) + from sage.combinat.partition import Partition + conj = self.shape.conjugate() + num = 1 + den = 1 + for i,l in enumerate(self.shape): + for j in range(l): + num *= (self.max_entry + j -i) + den *= (l + conj[j] - i - j - 1) + return Integer(num / den) class SemistandardTableaux_shape_weight(SemistandardTableaux_shape): r""" From c52abe98ec76e46281239b06388d0c01a7e9ea06 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 23 Apr 2015 08:58:40 -0700 Subject: [PATCH 491/665] Reverting some changes for speed. --- src/sage/combinat/sf/macdonald.py | 36 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index b4ffbf973f2..5edd30436d8 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -664,25 +664,21 @@ def cmunu1(mu, nu): True """ q,t = QQqt.gens() - # The following is equivalent to: + # The following for loop is equivalent to: # r,c = SkewPartition([mu,nu]).cells()[0] - for i, val in enumerate(nu): - if val < mu[i]: - r,c = i, val - break - else: - r,c = len(nu), 0 - - if r < len(nu): - A = prod((t**mu.leg_length(r, s) - q**(mu.arm_length(r, s)+1)) - / (t**nu.leg_length(r, s) - q**(nu.arm_length(r, s)+1)) - for s in range(nu[r])) - else: - A = QQqt.one() - B = prod((q**mu.arm_length(*s) - t**(mu.leg_length(*s)+1)) - / (q**nu.arm_length(*s) - t**(nu.leg_length(*s)+1)) - for s in nu.cells() if s[1] == c) - return QQqt(A * B) + for i, val in enumerate(nu._list): + if val < mu._list[i]: + A = prod((t**mu.leg_length(i, s) - q**(mu.arm_length(i, s)+1)) + / (t**nu.leg_length(i, s) - q**(nu.arm_length(i, s)+1)) + for s in range(val)) + B = prod((q**mu.arm_length(*s) - t**(mu.leg_length(*s)+1)) + / (q**nu.arm_length(*s) - t**(nu.leg_length(*s)+1)) + for s in nu.cells() if s[1] == val) + return QQqt(A * B) + + return QQqt(prod( (q**mu.arm_length(s, 0) - t**(mu.leg_length(s, 0)+1)) + / (q**nu.arm_length(s, 0) - t**(nu.leg_length(s, 0)+1)) + for s in range(len(nu._list)) )) @cached_function def cmunu(mu, nu): @@ -1361,7 +1357,7 @@ def _self_to_m(self, x): tinv = ~self.t return self._m._from_dict({ part2: self._base( sum(c * self.t**mu.weighted_size() - * self._Lmunu(part2, mu)(q=self.q, t=tinv) + * self._Lmunu(part2, mu).subs(q=self.q, t=tinv) for mu,c in x if self.degree_on_basis(mu) == d)) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) else: @@ -1595,7 +1591,7 @@ def _self_to_m(self, x): """ return self._m._from_dict({ part2: - self._base( sum(c * QQqt(self._Lmunu(part2, mu))(q=self.q, t=self.t) + self._base( sum(c * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) for mu, c in x if self.degree_on_basis(mu) == d) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) From b9447fd4de5991d0e147e538371123c221e14785 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 23 Apr 2015 09:22:17 -0700 Subject: [PATCH 492/665] Trying to get a little bit more. --- src/sage/combinat/sf/macdonald.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index eef85b7713b..df9e3a06b4d 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -711,9 +711,9 @@ def Bmu_skew(outer, inner): res += t**i * q**j return res - num = sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu_skew(al, nu) - for al in nu.up()) - return num / Bmu_skew(mu, nu) + nulist = nu._list + return (sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu_skew(al, nulist) + for al in nu.up()) / Bmu_skew(mu, nulist)) #Generic MacdonaldPolynomials class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): @@ -1331,7 +1331,7 @@ def _self_to_m(self, x): return self._m._from_dict({ part2: self._base( sum(c * self.t**mu.weighted_size() * self._Lmunu(part2, mu).subs(q=self.q, t=tinv) - for mu,c in x if self.degree_on_basis(mu) == d)) + for mu,c in x if sum(mu) == d)) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) else: return self._m(self._self_to_s(x)) @@ -1565,7 +1565,7 @@ def _self_to_m(self, x): """ return self._m._from_dict({ part2: self._base( sum(c * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) - for mu, c in x if sum(mu)==d) ) + for mu, c in x if sum(mu) == d) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) def _m_to_self( self, f ): From da67e9a2aa6c6c99a48ec6897c8726bc899982de Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 23 Apr 2015 14:24:02 -0400 Subject: [PATCH 493/665] changed the sum back for more speed --- src/sage/combinat/sf/macdonald.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index df9e3a06b4d..1a49a2eadb7 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1564,8 +1564,9 @@ def _self_to_m(self, x): """ return self._m._from_dict({ part2: - self._base( sum(c * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) - for mu, c in x if sum(mu) == d) ) + self._base( sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, + mu)).subs(q=self.q, t=self.t) + for mu in x.homogeneous_component(d).support()) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) def _m_to_self( self, f ): From b2d3ea7f504b5a2c363402ff2d0e2e7b4f844c49 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 23 Apr 2015 11:54:55 -0700 Subject: [PATCH 494/665] Getting some more time. --- src/sage/combinat/sf/macdonald.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 1a49a2eadb7..472aa17dcd0 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1328,10 +1328,11 @@ def _self_to_m(self, x): """ if self.t: tinv = ~self.t + part_coeff = lambda x, d: sorted((mu,c) for mu,c in x if sum(mu) == d) return self._m._from_dict({ part2: self._base( sum(c * self.t**mu.weighted_size() * self._Lmunu(part2, mu).subs(q=self.q, t=tinv) - for mu,c in x if sum(mu) == d)) + for mu,c in part_coeff(x, d)) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) else: return self._m(self._self_to_s(x)) @@ -1563,10 +1564,11 @@ def _self_to_m(self, x): ((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3] """ + part_coeff = lambda x, d: sorted((mu,c) for mu,c in x if sum(mu) == d) return self._m._from_dict({ part2: - self._base( sum(x.coefficient(mu) * QQqt(self._Lmunu(part2, + self._base( sum(c * QQqt(self._Lmunu(part2, mu)).subs(q=self.q, t=self.t) - for mu in x.homogeneous_component(d).support()) ) + for mu,c in part_coeff(x, d)) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) def _m_to_self( self, f ): From 5424fac7ab4d98e1526536956a00157c2dbcb2c4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 23 Apr 2015 11:57:08 -0700 Subject: [PATCH 495/665] Removing useless call to QQqt. --- src/sage/combinat/sf/macdonald.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 472aa17dcd0..29b3b105e62 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -1566,8 +1566,7 @@ def _self_to_m(self, x): """ part_coeff = lambda x, d: sorted((mu,c) for mu,c in x if sum(mu) == d) return self._m._from_dict({ part2: - self._base( sum(c * QQqt(self._Lmunu(part2, - mu)).subs(q=self.q, t=self.t) + self._base( sum(c * self._Lmunu(part2, mu).subs(q=self.q, t=self.t) for mu,c in part_coeff(x, d)) ) for d in range(x.degree()+1) for part2 in Partitions_n(d) }) From 8815433a50b356d25a0be040d29c7224d6f4b1fb Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Thu, 23 Apr 2015 21:47:32 +0200 Subject: [PATCH 496/665] #17682: use documented function instead of constant --- src/sage/misc/cython.py | 10 +++++----- src/sage/misc/sageinspect.py | 29 ++++++++++++++++++++++------- src/sage_setup/clean.py | 8 ++++---- src/sage_setup/find.py | 4 ++-- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 7802f447c02..4b7b2b61dcd 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -378,13 +378,13 @@ def cython(filename, verbose=False, compile_message=False, # There is already a module here. Maybe we do not have to rebuild? # Find the name. if use_cache: - from sage.misc.sageinspect import generic_so_extension - prev_so = [F for F in os.listdir(build_dir) if F[-len(generic_so_extension):] == generic_so_extension] + from sage.misc.sageinspect import shared_lib_extension + prev_so = [F for F in os.listdir(build_dir) if F.endswith(shared_lib_extension())] if len(prev_so) > 0: prev_so = prev_so[0] # should have length 1 because of deletes below if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(build_dir, prev_so)): # We do not have to rebuild. - return prev_so[:-len(generic_so_extension)], build_dir + return prev_so[:-len(shared_lib_extension())], build_dir else: os.makedirs(build_dir) for F in os.listdir(build_dir): @@ -544,8 +544,8 @@ def cython(filename, verbose=False, compile_message=False, if create_local_so_file: # Copy from lib directory into local directory - from sage.misc.sageinspect import generic_so_extension - cmd = 'cp %s/%s%s %s'%(build_dir, name, generic_so_extension, os.path.abspath(os.curdir)) + from sage.misc.sageinspect import shared_lib_extension + cmd = 'cp %s/%s%s %s'%(build_dir, name, shared_lib_extension(), os.path.abspath(os.curdir)) if os.system(cmd): raise RuntimeError("Error making local copy of shared object library for {}".format(filename)) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 6c9aec20b6d..70542f70938 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -118,14 +118,29 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return import os import tokenize import types -import sys EMBEDDED_MODE = False from sage.env import SAGE_SRC -if sys.platform == 'cygwin': - generic_so_extension = os.path.extsep + 'dll' -else: - generic_so_extension = os.path.extsep + 'so' +def shared_lib_extension(): + r""" + Return the filename extension of shared libraries, including the dot. + It is '.dll' on cygwin, '.so' otherwise. + + EXAMPLES:: + + sage: from site import getsitepackages + sage: site_packages = getsitepackages()[0] + sage: from sage_setup.find import installed_files_by_module + sage: files_by_module = installed_files_by_module(site_packages) + sage: from sage.misc.sageinspect import shared_lib_extension + sage: files_by_module['sage.structure.sage_object'].pop().endswith(shared_lib_extension()) + True + """ + import sys + if sys.platform == 'cygwin': + return os.path.extsep+'dll' + else: + return os.path.extsep+'so' def isclassinstance(obj): r""" @@ -1181,8 +1196,8 @@ def sage_getfile(obj): # No go? fall back to inspect. sourcefile = inspect.getabsfile(obj) - if sourcefile.endswith(generic_so_extension): - return sourcefile[:-len(generic_so_extension)]+os.path.extsep+'pyx' + if sourcefile.endswith(shared_lib_extension()): + return sourcefile[:-len(shared_lib_extension())]+os.path.extsep+'pyx' return sourcefile def sage_getargspec(obj): diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index 3ba50c80e61..f56f60e5b51 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -80,14 +80,14 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module extension modules:: sage: stale_iter = _find_stale_files(SAGE_LIB, python_packages, python_modules, []) - sage: from sage.misc.sageinspect import generic_so_extension + sage: from sage.misc.sageinspect import shared_lib_extension sage: for f in stale_iter: - ....: if f.endswith(generic_so_extension): continue + ....: if f.endswith(shared_lib_extension()): continue ....: print('Found stale file: ' + f) """ PYMOD_EXTS = (os.path.extsep + 'py', os.path.extsep + 'pyc') - from sage.misc.sageinspect import generic_so_extension - CEXTMOD_EXTS = (generic_so_extension,) + from sage.misc.sageinspect import shared_lib_extension + CEXTMOD_EXTS = (shared_lib_extension(),) INIT_FILES= map(lambda x: '__init__' + x, PYMOD_EXTS) module_files = installed_files_by_module(site_packages, ['sage', 'sage_setup']) diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index 41a8a23a16a..8aff82badfb 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -100,9 +100,9 @@ def installed_files_by_module(site_packages, modules=('sage',)): sage: from site import getsitepackages sage: site_packages = getsitepackages()[0] sage: files_by_module = installed_files_by_module(site_packages) - sage: from sage.misc.sageinspect import generic_so_extension + sage: from sage.misc.sageinspect import shared_lib_extension sage: files_by_module['sage.structure.sage_object'] == \ - ....: {'sage/structure/sage_object' + generic_so_extension} + ....: {'sage/structure/sage_object' + shared_lib_extension()} True sage: sorted(files_by_module['sage.structure']) ['sage/structure/__init__.py', 'sage/structure/__init__.pyc'] From 226800b0426be738e63b74ce3758fc38d3094c9b Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 23 Apr 2015 18:47:36 -0400 Subject: [PATCH 497/665] 18271 Added choice of algorithm Fixed spelling error 'Corallary' Made old algorithm accessible with algorithm='sum' --- src/sage/combinat/tableau.py | 40 ++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index face0553c2c..0d9cbb2b498 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5348,10 +5348,19 @@ def _repr_(self): """ return "Semistandard tableaux of shape %s and maximum entry %s" %(str(self.shape), str(self.max_entry)) - def cardinality(self): + def cardinality(self, algorithm='hook'): r""" Returns the cardinality of ``self``. + + INPUT: + + - ``algorithm`` -- (Default: ``'hook'``) any one of the following: + + - ``'hook'`` -- Use Stanley's hook formula + + - ``'sum'`` -- Sum over the compositions of ``max_entry`` the number of semistandard tableau with ``shape`` and given weight vector. + This is computed using *Stanley's hook length formula* .. MATH:: @@ -5360,7 +5369,7 @@ def cardinality(self): where `n` is the ``max_entry``, `c(u)` is the content of `u` and `h(u)` is the hook length of `u`. - See [Sta99] Corallary 7.21.4. + See [Sta99] Corollary 7.21.4. EXAMPLES:: @@ -5378,6 +5387,9 @@ def cardinality(self): 2352 sage: SemistandardTableaux([6,5,4,3,2,1], max_entry=30).cardinality() 208361017592001331200 + sage: ssts = [SemistandardTableaux(p, max_entry=6) for p in Partitions(5)] + sage: all(sst.cardinality() == sst.cardinality(algorithm='sum') for sst in ssts) + True REFERENCES: @@ -5387,15 +5399,21 @@ def cardinality(self): Cambridge University Press, 1999 """ - from sage.combinat.partition import Partition - conj = self.shape.conjugate() - num = 1 - den = 1 - for i,l in enumerate(self.shape): - for j in range(l): - num *= (self.max_entry + j -i) - den *= (l + conj[j] - i - j - 1) - return Integer(num / den) + if algorithm == 'hook': + conj = self.shape.conjugate() + num = 1 + den = 1 + for i,l in enumerate(self.shape): + for j in range(l): + num *= (self.max_entry + j -i) + den *= (l + conj[j] - i - j - 1) + return Integer(num / den) + elif algorithm == 'sum': + c = 0 + for comp in IntegerVectors(sum(self.shape), self.max_entry): + c += SemistandardTableaux_shape_weight(self.shape, Composition(comp)).cardinality() + return c + raise ValueError("unknown algorithm %r" % algorithm) class SemistandardTableaux_shape_weight(SemistandardTableaux_shape): r""" From b1830c3616ea2985892200e1be2c5a0c1016446d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 23 Apr 2015 18:07:52 -0700 Subject: [PATCH 498/665] Full coverage and some fixes and cleanup. --- .../root_system/integrable_representations.py | 534 +++++++++++------- 1 file changed, 323 insertions(+), 211 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index c777231d4a1..b5623276a03 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -13,20 +13,17 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.category_object import CategoryObject from sage.categories.modules import Modules -from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.root_system.root_space import RootSpace -from sage.combinat.root_system.weight_space import WeightSpace -from sage.rings.all import ZZ, QQ +from sage.rings.all import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import Matrix -from sage.functions.other import floor from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.combinat.root_system.weyl_characters import WeylCharacterRing # TODO: Make this a proper parent and implement actions class IntegrableRepresentation(CategoryObject, UniqueRepresentation): r""" - An irreducible highest weight representation of an affine Lie algebra. + An irreducible integrable highest weight representation of + an affine Lie algebra. INPUT: @@ -46,23 +43,24 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): functions and modular forms. Adv. in Math. 53 (1984), no. 2, 125-264. If `\Lambda` is a dominant integral weight for an affine root system, - there exists a unique integrable representation `V=V_\Lambda` of highest weight - `\Lambda`. If `\mu` is another weight, let `m(\mu)` denote the + there exists a unique integrable representation `V=V_\Lambda` of highest + weight `\Lambda`. If `\mu` is another weight, let `m(\mu)` denote the multiplicity of the weight `\mu` in this representation. The set `\text{supp}(V)` of `\mu` such that `m(\mu)>0` is contained in the paraboloid .. MATH:: - (\Lambda+\rho|\Lambda+\rho) - (\mu+\rho|\mu+\rho) \ge 0 + + (\Lambda+\rho | \Lambda+\rho) - (\mu+\rho | \mu+\rho) \geq 0 where `(\,|\,)` is the invariant inner product on the weight lattice and `\rho` is the Weyl vector. Moreover every `\mu` differs from - `\Lambda` by an element of the root lattice. ([Kac], Propositions 11.3 and - 11.4) such that `\Lambda - \mu` is in the root lattice, then multiplicity - of `\mu` in this representation will be denoted `m(\mu)`. + `\Lambda` by an element of the root lattice. ([Kac]_, Propositions 11.3 + and 11.4) such that `\Lambda - \mu` is in the root lattice, then + multiplicity of `\mu` in this representation will be denoted `m(\mu)`. Let `\delta` be the nullroot, which is the lowest positive imaginary - root. Then by [Kac], Proposition 11.3 or Corollary 11.9, for fixed `\mu` + root. Then by [Kac]_, Proposition 11.3 or Corollary 11.9, for fixed `\mu` the function `m(\mu - k\delta)` is a monotone increasing function of `k`. It is useful to take `\mu` to be such that this function is nonzero if and only if `k \geq 0`. Therefore we make the following definition. If @@ -71,8 +69,8 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): Since `\delta` is fixed under the action of the affine Weyl group, and since the weight multiplicities are Weyl group invariant, the - function `k \mapsto m(\mu-k\delta)` is unchanged if `\mu` is replaced by - an equivalent weight. Therefore in tabulating these functions, we may + function `k \mapsto m(\mu - k \delta)` is unchanged if `\mu` is replaced + by an equivalent weight. Therefore in tabulating these functions, we may assume that `\mu` is dominant. There are only a finite number of dominant maximal weights. @@ -81,27 +79,27 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): weights `\mu`, it is important to be able to compute these. We may do this as follows. - EXAMPLE:: + EXAMPLES:: sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).strings() + sage: IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]).print_strings() 2*Lambda[0] + Lambda[2]: 4 31 161 665 2380 7658 22721 63120 166085 417295 1007601 2349655 Lambda[0] + 2*Lambda[1]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[0] + 2*Lambda[3]: 2 18 99 430 1593 5274 16005 45324 121200 308829 754884 1779570 Lambda[1] + Lambda[2] + Lambda[3]: 1 10 60 274 1056 3601 11199 32354 88009 227555 563390 1343178 3*Lambda[2] - delta: 3 21 107 450 1638 5367 16194 45687 121876 310056 757056 1783324 sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(Lambda[0]+Lambda[1]).strings() # long time + sage: IntegrableRepresentation(Lambda[0]+Lambda[1]).print_strings() # long time Lambda[0] + Lambda[1]: 1 10 62 293 1165 4097 13120 38997 109036 289575 735870 1799620 Lambda[3] + Lambda[4] - delta: 3 25 136 590 2205 7391 22780 65613 178660 463842 1155717 2777795 In this example, we construct the extended weight lattice of Cartan type `A_3^{(1)}`, then define ``Lambda`` to be the fundamental - weights. We find there are 5 maximal dominant weights in irreducible - representation of highest weight ``Lambda[1]+Lambda[2]+Lambda[3]``, - and we determine their strings. + weights `(\Lambda_i)_{i \in I}`. We find there are 5 maximal + dominant weights in irreducible representation of highest weight + `\Lambda_1 + \Lambda_2 + \Lambda_3`, and we determine their strings. - It was shown in [KacPeterson] that each string is the set of Fourier + It was shown in [KacPeterson]_ that each string is the set of Fourier coefficients of a modular form. Every weight `\mu` such that the weight multiplicity `m(\mu)` is @@ -112,12 +110,12 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): \Lambda - n_0 \alpha_0 - n_1 \alpha_1 - \cdots, where the `n_i` are nonnegative integers. This is represented internally - as a tuple ``(n0, n1, n2, ...)``. If you want an individual multiplicity - you use the method ``m`` and supply it with this tuple:: + as a tuple `(n_0, n_1, n_2, \ldots)`. If you want an individual + multiplicity you use the method :meth:`m` and supply it with this tuple:: sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]); v - The Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] + Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] sage: v.m((3,5,3)) 18 @@ -125,7 +123,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): and :meth:`from_weight` to convert between this internal representation and the weight lattice:: - sage: delta = v.null_root() + sage: delta = v.weight_lattice().null_root() sage: v.to_weight((4,3,2)) -3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta sage: v.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) @@ -135,7 +133,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): sage: L0 = RootSystem(["A",1,1]).weight_lattice(extended=true).fundamental_weight(0); L0 Lambda[0] - sage: IntegrableRepresentation(4*L0).strings(depth=20) + sage: IntegrableRepresentation(4*L0).print_strings(depth=20) 4*Lambda[0]: 1 1 3 6 13 23 44 75 131 215 354 561 889 1368 2097 3153 4712 6936 10151 14677 2*Lambda[0] + 2*Lambda[1] - delta: 1 2 5 10 20 36 66 112 190 310 501 788 1230 1880 2850 4256 6303 9222 13396 19262 4*Lambda[1] - 2*delta: 1 2 6 11 23 41 75 126 215 347 561 878 1368 2082 3153 4690 6936 10121 14677 21055 @@ -144,7 +142,7 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: v.strings() # long time + sage: v.print_strings() # long time 2*Lambda[0]: 1 2 9 26 77 194 477 1084 2387 5010 10227 20198 Lambda[0] + Lambda[2] - delta: 1 5 18 55 149 372 872 1941 4141 8523 17005 33019 2*Lambda[1] - delta: 1 4 15 44 122 304 721 1612 3469 7176 14414 28124 @@ -153,11 +151,17 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): def __init__(self, Lam): """ Initialize ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]) + sage: TestSuite(v).run() """ CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ)) - if not Lam.parent()._extended: - raise ValueError("The parent of %s must be an extended affine root lattice."%Lam) + if not Lam.parent().cartan_type().is_affine() or not Lam.parent()._extended: + raise ValueError("the parent of %s must be an extended affine root lattice"%Lam) self._Lam = Lam self._P = Lam.parent() self._Q = self._P.root_system.root_lattice() @@ -165,7 +169,7 @@ def __init__(self, Lam): self._cartan_matrix = self._P.root_system.cartan_matrix() self._cartan_type = self._P.root_system.cartan_type() if not self._cartan_type.is_untwisted_affine(): - raise NotImplementedError("Integrable Representations are only implemented for Untwisted Affine Types.") + raise NotImplementedError("integrable representations are only implemented for untwisted affine types") self._classical_rank = self._cartan_type.classical().rank() self._index_set = self._P.index_set() self._index_set_classical = self._cartan_type.classical().index_set() @@ -173,40 +177,35 @@ def __init__(self, Lam): self._ddict = {} self._mdict = {tuple(0 for i in self._index_set): 1} - self._rho = self._P.rho() - self._delta = self._Q.null_root() # Coerce a classical root into the root lattice Q from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) self._classical_roots = [from_cl_root(al) for al in self._Q.classical().roots()] self._classical_positive_roots = [from_cl_root(al) for al in self._Q.classical().positive_roots()] - self._eps = {i: self._cartan_type.a()[i] / self._cartan_type.dual().a()[i] - for i in self._index_set} - self._a = self._cartan_type.a() - self._ac = self._cartan_type.dual().a() - self._coxeter_number = sum(self._a[i] for i in self._index_set) - self._dual_coxeter_number = sum(self._ac[i] for i in self._index_set) + self._a = self._cartan_type.a() # This is not cached + self._ac = self._cartan_type.dual().a() # This is not cached + self._eps = {i: self._a[i] / self._ac[i] for i in self._index_set} + self._coxeter_number = sum(self._a) + self._dual_coxeter_number = sum(self._ac) E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical]) self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse() - self._den0 = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho) def highest_weight(self): """ - Returns the highest weight of the IntegrableRepresentation ``self``. + Returns the highest weight of ``self``. EXAMPLES:: sage: Lambda = RootSystem(['D',4,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(Lambda[0]+2*Lambda[2]).highest_weight() Lambda[0] + 2*Lambda[2] - """ return self._Lam def weight_lattice(self): """ - Returns the Weight Lattice of ``self``. + Return the weight lattice associated to ``self``. EXAMPLES:: @@ -214,12 +213,11 @@ def weight_lattice(self): sage: v.weight_lattice() Extended weight lattice of the Root system of type ['E', 6, 1] """ - return self._P def root_lattice(self): """ - Returns the Root Lattice of ``self``. + Return the root lattice associated to ``self``. EXAMPLES:: @@ -229,47 +227,27 @@ def root_lattice(self): """ return self._Q - def null_root(self): - """ - Returns the nullroot of ``self``. - - EXAMPLES:: - - sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v=IntegrableRepresentation(Lambda[0]) - sage: delta = v.null_root(); delta - alpha[0] + 3*alpha[1] + 2*alpha[2] - """ - return self._delta - - def rho(self): - """ - Returns the Weyl vector `\\rho`. - - EXAMPLES:: - - sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(Lambda[0]).rho() - Lambda[0] + Lambda[1] + Lambda[2] - """ - return self._rho - + @cached_method def level(self): """ - The level of the representation equals `(\Lambda|\delta)`. See [Kac] section 12.4. + Return the level of ``self``. + + The level of a highest weight representation `B(\Lambda)` is + defined as `(\Lambda | \delta)` See [Kac]_ section 12.4. EXAMPLES:: sage: Lambda = RootSystem(['G',2,1]).weight_lattice(extended=true).fundamental_weights() sage: [IntegrableRepresentation(Lambda[i]).level() for i in [0,1,2]] [1, 1, 2] - """ - return ZZ(self._inner_pq(self._Lam, self._delta)) + return ZZ(self._inner_pq(self._Lam, self._Q.null_root())) def coxeter_number(self): """ - The dual Coxeter number is defined in [Kac] Chapter 6, and commonly + Return the Coxeter number of the Cartan type of ``self``. + + The Coxeter number is defined in [Kac]_ Chapter 6, and commonly denoted `h`. EXAMPLES:: @@ -278,14 +256,15 @@ def coxeter_number(self): sage: v = IntegrableRepresentation(Lambda[0]) sage: v.coxeter_number() 12 - """ return self._coxeter_number def dual_coxeter_number(self): - """ - The dual Coxeter number is defined in [Kac] Chapter 6, and commonly - denoted `h^\\vee`. + r""" + Return the dual Coxeter number of the Cartan type of ``self``. + + The dual Coxeter number is defined in [Kac]_ Chapter 6, and commonly + denoted `h^{\vee}`. EXAMPLES:: @@ -293,28 +272,54 @@ def dual_coxeter_number(self): sage: v = IntegrableRepresentation(Lambda[0]) sage: v.dual_coxeter_number() 9 - """ return self._dual_coxeter_number - def __repr__(self): + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: IntegrableRepresentation(Lambda[0]) + Integrable representation of ['F', 4, 1] with highest weight Lambda[0] + """ + return "Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) + + def _latex_(self): """ - Return a representation of ``self``. + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]+2*Lambda[3]) + sage: latex(v) + B(\Lambda_{0} + 2\Lambda_{3}) """ - return "The Integrable representation of %s with highest weight %s"%(self._cartan_type, self._Lam) + return "B({})".format(self._Lam._latex_()) def cartan_type(self): """ - Return the Cartan Type of ``self``. + Return the Cartan type of ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]) + sage: v.cartan_type() + ['F', 4, 1] """ return self._cartan_type def _inner_qq(self, qelt1, qelt2): """ - Symmetric form between two elements of the root lattice. - + Symmetric form between two elements of the root lattice + associated to ``self``. + EXAMPLES:: - + sage: P = RootSystem(['F',4,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() sage: v = IntegrableRepresentation(Lambda[0]) @@ -333,7 +338,7 @@ def _inner_qq(self, qelt1, qelt2): and it will be wrong. To make this code robust, parents should be checked. This is not done since in the application the parents are known, so checking would unnecessarily slow -= us down. + us down. """ mc1 = qelt1.monomial_coefficients() mc2 = qelt2.monomial_coefficients() @@ -344,7 +349,8 @@ def _inner_qq(self, qelt1, qelt2): def _inner_pq(self, pelt, qelt): """ - Symmetric form between an element of the weight and root lattices. + Symmetric form between an element of the weight and root lattices + associated to ``self``. .. WARNING: @@ -383,7 +389,8 @@ def _inner_pq(self, pelt, qelt): def _inner_pp(self, pelt1, pelt2): """ - Symmetric form between an two elements of the weight lattice. + Symmetric form between an two elements of the weight lattice + associated to ``self``. EXAMPLES:: @@ -399,32 +406,37 @@ def _inner_pp(self, pelt1, pelt2): [ 0 0 0] [ 0 2/3 1] [ 0 1 2] - """ mc1 = pelt1.monomial_coefficients() mc2 = pelt2.monomial_coefficients() - return sum(mc1.get(i,0)*self._ac[i]*mc2.get('delta',0) for i in self._index_set) +\ - sum(mc2.get(i,0)*self._ac[i]*mc1.get('delta',0) for i in self._index_set) +\ - sum(mc1.get(i,0)*mc2.get(j,0)*self._ip[i-1][j-1] for i in self._index_set_classical for j in self._index_set_classical) + zero = ZZ.zero() + mc1d = mc1.get('delta', zero) + mc2d = mc2.get('delta', zero) + return sum(mc1.get(i,zero) * self._ac[i] * mc2d + + mc2.get(i,zero) * self._ac[i] * mc1d + for i in self._index_set) \ + + sum(mc1.get(i,zero) * mc2.get(j,zero) * self._ip[ii,ij] + for ii, i in enumerate(self._index_set_classical) + for ij, j in enumerate(self._index_set_classical)) def to_weight(self, n): - """ - INPUT: - - - ``n`` -- a tuple representing a weight. + r""" + Return the weight associated to the tuple ``n`` in ``self``. - Returns the weight associated to the tuple ``n``. If ``n`` - is the tuple `(n_1, n_2, \ldots)`, then the associated - weight is `\Lambda - \sum_i n_i \\alpha_i`, where `\Lambda` + If ``n`` is the tuple `(n_1, n_2, \ldots)`, then the associated + weight is `\Lambda - \sum_i n_i \alpha_i`, where `\Lambda` is the weight of the representation. + INPUT: + + - ``n`` -- a tuple representing a weight + EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(2*Lambda[2]) sage: v.to_weight((1,0,0)) -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta - """ alpha = self._P.simple_roots() I = self._index_set @@ -433,7 +445,11 @@ def to_weight(self, n): def _from_weight_helper(self, mu, check=False): r""" - Return ``(n[0], n[1], ...)`` such that ``mu = sum n[i]*alpha[i]``. + Return the coefficients of a tuple of the weight ``mu`` expressed + in terms of the simple roots in ``self``. + + The tuple ``n`` is defined as the tuple `(n_0, n_1, \ldots)` + such that `\mu = \sum_{i \in I} n_i \alpha_i`. INPUT: @@ -443,25 +459,37 @@ def _from_weight_helper(self, mu, check=False): Implement this as a section map of the inverse of the coercion from `Q \to P`. + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[2]) + sage: v.to_weight((1,0,0)) + -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta + sage: delta = v.weight_lattice().null_root() + sage: v._from_weight_helper(2*Lambda[0] - Lambda[1] - 1*Lambda[2] + delta) + (1, 0, 0) """ mu = self._P(mu) - n0 = mu.monomial_coefficients().get('delta', 0) - mu0 = mu - n0*self._P.simple_root(self._cartan_type.special_node()) + zero = ZZ.zero() + n0 = mu.monomial_coefficients().get('delta', zero) + mu0 = mu - n0 * self._P.simple_root(self._cartan_type.special_node()) ret = [n0] # This should be in ZZ because it is in the weight lattice mc_mu0 = mu0.monomial_coefficients() - zero = ZZ.zero() - for i in self._index_set_classical: + for ii, i in enumerate(self._index_set_classical): # -1 for indexing - ret.append( sum(self._cminv[i-1,j-1] * mc_mu0.get(j, zero) - for j in self._index_set_classical) ) + ret.append( sum(self._cminv[ii,ij] * mc_mu0.get(j, zero) + for ij, j in enumerate(self._index_set_classical)) ) if check: return all(x in ZZ for x in ret) else: return tuple(ZZ(x) for x in ret) - + def from_weight(self, mu): - """ - Return ``(n[0], n[1], ...)`` such that ``mu = Lam - sum n[i]*alpha[i]`` + r""" + Return the tuple `(n_0, n_1, ...)`` such that ``mu`` equals + `\Lambda - sum_{i \in I} n_i \alpha_i` in ``self``, where `\Lambda` + is the highest weight of ``self``. EXAMPLES:: @@ -469,24 +497,22 @@ def from_weight(self, mu): sage: v = IntegrableRepresentation(2*Lambda[2]) sage: v.to_weight((1,0,0)) -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta - sage: delta = v.null_root() + sage: delta = v.weight_lattice().null_root() sage: v.from_weight(-2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta) (1, 0, 0) - """ return self._from_weight_helper(self._Lam - mu) def s(self, n, i): """ - Implements the `i`-th simple reflection in the internal - representation of weights by tuples. + Return the action of the ``i``-th simple reflection on the + internal representation of weights by tuples ``n`` in ``self``. EXAMPLES:: sage: v = IntegrableRepresentation(RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weight(0)) sage: [v.s((0,0,0),i) for i in v._index_set] [(1, 0, 0), (0, 0, 0), (0, 0, 0)] - """ ret = list(n) # This makes a copy ret[i] += self._Lam._monomial_coefficients.get(i, ZZ.zero()) @@ -495,7 +521,8 @@ def s(self, n, i): def to_dominant(self, n): """ - Return the dominant weight equivalent to ``n`` under the affine Weyl group. + Return the dominant weight in ``self`` equivalent to ``n`` + under the affine Weyl group. EXAMPLES:: @@ -543,18 +570,47 @@ def to_dominant(self, n): def _freudenthal_roots_imaginary(self, nu): r""" - It is assumed that ``nu`` is in `Q`. Returns the set of imaginary - roots `\alpha \in \Delta^+` such that `\\nu - \alpha \in Q^+`. + Return the set of imaginary roots `\alpha \in \Delta^+` in ``self`` + such that `\nu - \alpha \in Q^+`. + + INPUT: + + - ``nu`` -- an element in `Q` + + EXAMPLES:: + + sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: [v._freudenthal_roots_imaginary(v.highest_weight() - mw) + ....: for mw in v.dominant_maximal_weights()] + [[], [], [], [], []] """ l = self._from_weight_helper(nu) - kp = min(floor(l[i] / self._a[i]) for i in self._index_set) + kp = min(l[i] // self._a[i] for i in self._index_set) delta = self._Q.null_root() - return [u*delta for u in range(1, kp+1)] + return [u * delta for u in range(1, kp+1)] def _freudenthal_roots_real(self, nu): r""" - It is assumed that ``nu`` is in `Q`. Returns the set of real positive - roots `\alpha \in \Delta^+` such that `\\nu - \alpha \in Q^+`. + Return the set of real positive roots `\alpha \in \Delta^+` in + ``self`` such that `\nu - \alpha \in Q^+`. + + INPUT: + + - ``nu`` -- an element in `Q` + + EXAMPLES:: + + sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: mw = v.dominant_maximal_weights()[0] + sage: v._freudenthal_roots_real(v.highest_weight() - mw) + [alpha[1], + alpha[2], + alpha[3], + alpha[1] + alpha[2], + alpha[2] + alpha[3], + alpha[1] + alpha[2] + alpha[3]] """ ret = [] for al in self._classical_positive_roots: @@ -567,7 +623,16 @@ def _freudenthal_roots_real(self, nu): def _freudenthal_accum(self, nu, al): """ - Helper method for computing the Freudenthal formula. + Helper method for computing the Freudenthal formula in ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: mw = v.dominant_maximal_weights()[0] + sage: F = v._freudenthal_roots_real(v.highest_weight() - mw) + sage: [v._freudenthal_accum(mw, al) for al in F] + [4, 4, 3, 4, 3, 3] """ ret = 0 n = list(self._from_weight_helper(self._Lam - nu)) @@ -587,7 +652,17 @@ def _freudenthal_accum(self, nu, al): def _m_freudenthal(self, n): """ - Compute the weight multiplicity using the Freudenthal multiplicity formula. + Compute the weight multiplicity using the Freudenthal + multiplicity formula in ``self``. + + EXAMPLES:: + + sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: D = list(v.dominant_maximal_weights()) + sage: D.remove(v.highest_weight()) + sage: [v._m_freudenthal(v.from_weight(mw)) for mw in D] + [3, 7, 3, 3] """ if min(n) < 0: return 0 @@ -601,27 +676,25 @@ def _m_freudenthal(self, n): num += self._freudenthal_accum(mu, al) for al in self._freudenthal_roots_imaginary(self._Lam - mu): num += self._classical_rank * self._freudenthal_accum(mu, al) - if den == 0 and num == 0: - print "_m_freudenthal","m: n=%s, num=den=0"%n.__repr__() try: return ZZ(num / den) - except: + except TypeError: return None def m(self, n): - """ + r""" + Return the multiplicity of the weight `\mu` in ``self``, where + `\mu = \Lambda - \sum_i n_i \alpha_i`. + INPUT: - ``n`` -- a tuple representing a weight `\mu`. - Return the multiplicity of the weight `\mu` in ``self``, where - `\mu = \Lambda - \sum_i n_i \\alpha_i`. - EXAMPLES:: sage: Lambda = RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(Lambda[0]) - sage: u = v.highest_weight()-v.null_root() + sage: u = v.highest_weight() - v.weight_lattice().null_root() sage: v.from_weight(u) (1, 1, 2, 2, 3, 2, 1) sage: v.m(v.from_weight(u)) @@ -632,27 +705,28 @@ def m(self, n): # - m # - _m_freudenthal # - _freudenthal_accum - if self._mdict.has_key(n): + if n in self._mdict: return self._mdict[n] - elif self._ddict.has_key(n): + elif n in self._ddict: self._mdict[n] = self.m(self._ddict[n]) m = self.to_dominant(n) - if self._mdict.has_key(m): + if m in self._mdict: return self._mdict[m] ret = self._m_freudenthal(m) - if ret is not None: - self._mdict[n] = ret - else: - print "m: error - failed to compute m%s"%n.__repr__() + assert ret is not None, "m: error - failed to compute m{}".format(n) + self._mdict[n] = ret return ret + @cached_method def dominant_maximal_weights(self): - """ - A weight `\\mu` is *maximal* if it has nonzero multiplicity but - `\\mu+\\delta`` has multiplicity zero. There are a finite number - of dominant maximal weights. Indeed, [Kac] Proposition 12.6 + r""" + Return the dominant maximal weights of ``self``. + + A weight `\mu` is *maximal* if it has nonzero multiplicity but + `\mu + \delta`` has multiplicity zero. There are a finite number + of dominant maximal weights. Indeed, [Kac]_ Proposition 12.6 shows that the dominant maximal weights are in bijection with - the classical weights in `k\cdot F` where `F` is the fundamental + the classical weights in `k \cdot F` where `F` is the fundamental alcove and `k` is the level. The construction used in this method is based on that Proposition. @@ -660,39 +734,50 @@ def dominant_maximal_weights(self): sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() sage: IntegrableRepresentation(2*Lambda[0]).dominant_maximal_weights() - [2*Lambda[0], - Lambda[0] + Lambda[2] - delta, - 2*Lambda[1] - delta, - Lambda[1] + Lambda[3] - 2*delta, - 2*Lambda[2] - 2*delta, - 2*Lambda[3] - 3*delta] - + (2*Lambda[0], + Lambda[0] + Lambda[2] - delta, + 2*Lambda[1] - delta, + Lambda[1] + Lambda[3] - 2*delta, + 2*Lambda[2] - 2*delta, + 2*Lambda[3] - 3*delta) """ k = self.level() Lambda = self._P.fundamental_weights() def next_level(wt): - return [wt + Lambda[i] for i in self._index_set_classical if (wt + Lambda[i]).level() <= k] + return [wt + Lambda[i] for i in self._index_set_classical + if (wt + Lambda[i]).level() <= k] R = RecursivelyEnumeratedSet([self._P.zero()], next_level) candidates = [x + (k - x.level())*Lambda[0] for x in list(R)] ret = [] + delta = self._Q.null_root() for x in candidates: if self._from_weight_helper(self._Lam-x, check=True): t = 0 - while self.m(self.from_weight(x-t*self._delta)) == 0: + while self.m(self.from_weight(x - t*delta)) == 0: t += 1 - ret.append(x-t*self._delta) - return ret + ret.append(x - t*delta) + return tuple(ret) def string(self, max_weight, depth=12): """ - Return the list of multiplicities `m(\Lambda - k \delta)` where - `\Lambda` is ``max_weight`` and `k` runs from `0` to ``depth``. + Return the list of multiplicities `m(\Lambda - k \delta)` in + ``self``, where `\Lambda` is ``max_weight`` and `k` runs from `0` + to ``depth``. INPUT: - ``max_weight`` -- a dominant maximal weight - ``depth`` -- (default: 12) the maximum value of `k` - """ + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[0]) + sage: v.string(2*Lambda[0]) + [1, 2, 8, 20, 52, 116, 256, 522, 1045, 1996, 3736, 6780] + sage: v.string(Lambda[1] + Lambda[2]) + [0, 1, 4, 12, 32, 77, 172, 365, 740, 1445, 2736, 5041] + """ ret = [] delta = self._Q.null_root() cur_weight = max_weight @@ -701,7 +786,6 @@ def string(self, max_weight, depth=12): cur_weight -= delta return ret - # FIXME: Return a dictionary def strings(self, depth=12): """ Return the set of dominant maximal weights of ``self``, together @@ -709,53 +793,73 @@ def strings(self, depth=12): OPTIONAL: - - ``depth`` -- a parameter indicating how far to push computations - - The depth parameter defaults to 12. + - ``depth`` -- (default: 12) a parameter indicating how far + to push computations EXAMPLES:: sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() - sage: IntegrableRepresentation(2*Lambda[0]).strings(depth=25) + sage: v = IntegrableRepresentation(2*Lambda[0]) + sage: S = v.strings(depth=25) + sage: for k in S: + ....: print "{}: {}".format(k, ' '.join(str(x) for x in S[k])) 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 + """ + return {max_weight: self.string(max_weight, depth) + for max_weight in self.dominant_maximal_weights()} + def print_strings(self, depth=12): """ - for max_weight in self.dominant_maximal_weights(): - s = self.string(max_weight, depth) - print "%s:"%max_weight, - for j in s: - print j, - print + Print the strings of ``self``. - def modular_characteristic(self, mu=None): + .. SEEALSO:: + + :meth:`strings` + + EXAMPLES:: + + sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() + sage: v = IntegrableRepresentation(2*Lambda[0]) + sage: v.print_strings(depth=25) + 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 + 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ + S = self.strings(depth=depth) + for mw in self.dominant_maximal_weights(): + print( "{}: {}".format(mw, ' '.join(str(x) for x in S[mw])) ) + + def modular_characteristic(self, mu=None): + r""" + Return the modular characteristic of ``self``. + The modular characteristic is a rational number introduced - by Kac and Peterson (1984), required to interpret the string - functions as Fourier coefficients of modular forms. See - [Kac] Section 12.7. Let `k` be the level, and let `h^\\vee` + by Kac and Peterson [KacPeterson]_, required to interpret the + string functions as Fourier coefficients of modular forms. See + [Kac]_ Section 12.7. Let `k` be the level, and let `h^\vee` be the dual Coxeter number. Then .. MATH:: - m_\Lambda = \\frac{|\Lambda+\\rho|^2}{2(k+h^\\vee)} - \\frac{|\\rho|^2}{2h^\\vee} + m_\Lambda = \frac{|\Lambda+\rho|^2}{2(k+h^\vee)} + - \frac{|\rho|^2}{2h^\vee} - If $\mu$ is a weight, then + If `\mu` is a weight, then .. MATH:: - m_{\Lambda,\mu} = m_\Lambda - \\frac{|\mu|^2}{2k}. - + m_{\Lambda,\mu} = m_\Lambda - \frac{|\mu|^2}{2k}. + OPTIONAL: - ``mu`` -- a weight; or alternatively: - ``n`` -- a tuple representing a weight `\mu`. - If not optional parameter is specified, The function returns `m_\Lambda`. - If ``mu`` is specified, it returns `m_{\Lambda,\mu}`. You may use the - tuple ``n`` to specify `\mu`. If you do this, `\mu` is - `\Lambda - \sum_i n_i \\alpha_i`. - + If no optional parameter is specified, this returns `m_\Lambda`. + If ``mu`` is specified, it returns `m_{\Lambda,\mu}`. You may + use the tuple ``n`` to specify `\mu`. If you do this, `\mu` is + `\Lambda - \sum_i n_i \alpha_i`. + EXAMPLES:: sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() @@ -769,16 +873,18 @@ def modular_characteristic(self, mu=None): n = self.from_weight(mu) k = self.level() hd = self._dual_coxeter_number - m_Lambda = self._inner_pp(self._Lam+self._rho, self._Lam+self._rho)/(2*(k+hd)) - \ - self._inner_pp(self._rho,self._rho)/(2*hd) + rho = self._P.rho() + m_Lambda = self._inner_pp(self._Lam+rho, self._Lam+rho) / (2*(k+hd)) \ + - self._inner_pp(rho, rho) / (2*hd) if n is None: return m_Lambda - else: - mu = self.to_weight(n) - return m_Lambda-self._inner_pp(mu,mu)/(2*k) + mu = self.to_weight(n) + return m_Lambda - self._inner_pp(mu,mu) / (2*k) + + def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): + r""" + Return the branching rule on ``self``. - def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): - """ Removing any node from the extended Dynkin diagram of the affine Lie algebra results in the Dynkin diagram of a classical Lie algebra, which is therefore a Lie subalgebra. For example @@ -795,13 +901,15 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): OPTIONAL: - - ``i`` -- an element of the index set (default 0) + - ``i`` -- (default: 0) an element of the index set - ``weyl_character_ring`` -- a WeylCharacterRing - ``sequence`` -- a dictionary - - ``depth`` -- an upper bound for `k` determining how many terms to give (default 5) + - ``depth`` -- (default: 5) an upper bound for `k` determining + how many terms to give - In the default case where `i=0`, you do not need to specify anything else, - though you may want to increase the depth if you need more terms. + In the default case where `i = 0`, you do not need to specify + anything else, though you may want to increase the depth if + you need more terms. EXAMPLES:: @@ -809,11 +917,11 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): sage: v = IntegrableRepresentation(2*Lambda[0]) sage: b = v.branch(); b [A2(0,0), - A2(1,1), - A2(0,0) + 2*A2(1,1) + A2(2,2), - 2*A2(0,0) + 2*A2(0,3) + 4*A2(1,1) + 2*A2(3,0) + 2*A2(2,2), - 4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1), - 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] + A2(1,1), + A2(0,0) + 2*A2(1,1) + A2(2,2), + 2*A2(0,0) + 2*A2(0,3) + 4*A2(1,1) + 2*A2(3,0) + 2*A2(2,2), + 4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1), + 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] If the parameter weyl_character_ring is omitted, the ring may be recovered as the parent of one of the branched coefficients:: @@ -834,9 +942,10 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): 1 2 3 B3~ - In this example, we observe that removing the `i=2` node from the Dynkin diagram - produces a reducible diagram of type ``A1xA1xA1``. Thus we have a branching - to `\mathfrak{sl}(2)\\times \mathfrak{sl}(2)\\times \mathfrak{sl}(2)`:: + In this example, we observe that removing the `i=2` node from the + Dynkin diagram produces a reducible diagram of type ``A1xA1xA1``. + Thus we have a branching to + `\mathfrak{sl}(2) \times \mathfrak{sl}(2) \times \mathfrak{sl}(2)`:: sage: A1xA1xA1 = WeylCharacterRing("A1xA1xA1",style="coroots") sage: v.branch(i=2,weyl_character_ring=A1xA1xA1) @@ -872,7 +981,7 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): The nodes `0, 2, 3, 4` of ``F4~`` correspond to ``1, 4, 3, 2`` of ``A1xC3`` and so we encode this in a dictionary:: - sage: v.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) + sage: v.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) # long time [A1xC3(1,0,0,0), A1xC3(0,0,0,1), A1xC3(1,0,0,0) + A1xC3(1,2,0,0), @@ -881,14 +990,16 @@ def branch(self, i=0, weyl_character_ring=None, sequence=None, depth=5): 2*A1xC3(2,0,0,1) + A1xC3(2,1,1,0) + A1xC3(0,1,0,0) + 3*A1xC3(0,0,0,1) + 2*A1xC3(0,1,1,0) + A1xC3(0,2,0,1)] """ - if i==0 or self.cartan_type()[0] == 'A': + if i is None: + i = self._cartan_type.special_node() + if i == self._cartan_type.special_node() or self._cartan_type.type() == 'A': if weyl_character_ring is None: - weyl_character_ring = WeylCharacterRing(self.cartan_type().classical(), style="coroots") - if weyl_character_ring.cartan_type() != self.cartan_type().classical(): - raise ValueError("Cartan Type of WeylCharacterRing must be %s"%self.cartan_type().classical()) + weyl_character_ring = WeylCharacterRing(self._cartan_type.classical(), style="coroots") + if weyl_character_ring.cartan_type() != self._cartan_type.classical(): + raise ValueError("Cartan type of WeylCharacterRing must be %s"%self.cartan_type().classical()) elif weyl_character_ring is None: - raise ValueError("""The argument "weyl_character_ring" cannot be omitted if "i != 0" """) - if sequence == None: + raise ValueError("the argument weyl_character_ring cannot be omitted if i != 0") + if sequence is None: sequence = {} for j in self._index_set: if j < i: @@ -901,7 +1012,6 @@ def next_level(x): t = list(x[0]) t[j] += 1 t = tuple(t) - u = self.to_weight(t) m = self.m(t) if m > 0 and t[i] <= depth: ret.append((t,m)) @@ -916,10 +1026,12 @@ def next_level(x): ldict = {} for x in lterms: mc = P(self.to_weight(x[0])).monomial_coefficients() - contr = sum(fw[sequence[j]]*mc.get(j,0) for j in self._index_set if j != i).coerce_to_sl() + contr = sum(fw[sequence[j]]*mc.get(j,0) + for j in self._index_set if j != i).coerce_to_sl() if ldict.has_key(contr): ldict[contr] += x[1] else: ldict[contr] = x[1] ret.append(weyl_character_ring.char_from_weights(ldict)) return ret + From 7766c554cd739b0f88bfc9ac51116c84e6a0d7b0 Mon Sep 17 00:00:00 2001 From: Darij Grinberg Date: Fri, 24 Apr 2015 08:01:04 +0200 Subject: [PATCH 499/665] review patch --- src/sage/categories/coxeter_groups.py | 56 ++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index cc0f4ab07b9..4cce4740c25 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -948,7 +948,7 @@ def is_grassmannian(self, side = "right"): def reduced_word_reverse_iterator(self): """ - Returns a reverse iterator on a reduced word for self. + Return a reverse iterator on a reduced word for ``self``. EXAMPLES:: @@ -963,7 +963,9 @@ def reduced_word_reverse_iterator(self): sage: sigma.length() 3 - SEE ALSO :meth:`.reduced_word` + .. SEEALSO:: + + :meth:`.reduced_word` Default implementation: recursively remove the first right descent until the identity is reached (see :meth:`.first_descent` and @@ -979,11 +981,12 @@ def reduced_word_reverse_iterator(self): def reduced_word(self): r""" - Returns a reduced word for self. + Return a reduced word for ``self``. This is a word `[i_1,i_2,\ldots,i_k]` of minimal length - such that `s_{i_1} s_{i_2} \cdots s_{i_k}=self`, where `s` - are the simple reflections. + such that + `s_{i_1} s_{i_2} \cdots s_{i_k} = \operatorname{self}`, + where the `s_i` are the simple reflections. EXAMPLES:: @@ -996,8 +999,10 @@ def reduced_word(self): sage: w.reduced_word() [2, 0] - SEE ALSO: :meth:`.reduced_words`, :meth:`.reduced_word_reverse_iterator`, :meth:`length` + .. SEEALSO:: + :meth:`.reduced_words`, :meth:`.reduced_word_reverse_iterator`, + :meth:`length`, :meth:`reduced_word_graph` """ result = list(self.reduced_word_reverse_iterator()) return list(reversed(result)) @@ -1007,7 +1012,10 @@ def reduced_word(self): def reduced_words(self): r""" - Returns all reduced words for self. + Return all reduced words for ``self``. + + See :meth:`reduced_word` for the definition of a reduced + word. EXAMPLES:: @@ -1023,6 +1031,11 @@ def reduced_words(self): TODO: the result should be full featured finite enumerated set (e.g. counting can be done much faster than iterating). + + .. SEEALSO:: + + :meth:`.reduced_word`, :meth:`.reduced_word_reverse_iterator`, + :meth:`length`, :meth:`reduced_word_graph` """ descents = self.descents() if descents == []: @@ -1038,9 +1051,14 @@ def reduced_word_graph(self): Return the reduced word graph of ``self``. The reduced word graph of an element `w` in a Coxeter group - is the graph whose vertices are reduced words `R_w` and there - is an `m`-colored edge between `x, y \in R_w` if `x` and `y` - differ by exactly one length `m` braid move. + is the graph whose vertices are the reduced words for `w` + (see :meth:`reduced_word` for a definition of this term), + and which has an `m`-colored edge between two reduced words + `x` and `y` whenever `x` and `y` differ by exactly one + length-`m` braid move (with `m \geq 2`). + + This graph is always connected (a theorem due to Tits) and + has no multiple edges. EXAMPLES:: @@ -1053,6 +1071,24 @@ def reduced_word_graph(self): 16 sage: G.num_edges() 18 + sage: len([e for e in G.edges() if e[2] == 2]) + 10 + sage: len([e for e in G.edges() if e[2] == 3]) + 8 + + TESTS:: + + sage: w1 = W.one() + sage: G = w1.reduced_word_graph() + sage: G.num_verts() + 1 + sage: G.num_edges() + 0 + + .. SEEALSO:: + + :meth:`.reduced_words`, :meth:`.reduced_word_reverse_iterator`, + :meth:`length`, :meth:`reduced_word` """ R = self.reduced_words() from sage.graphs.graph import Graph From fcb7e48e4459e2f39a855ba9ac0827448e6de3c6 Mon Sep 17 00:00:00 2001 From: Unknown User Date: Fri, 24 Apr 2015 07:44:31 +0000 Subject: [PATCH 500/665] No Subject. Modified: algebra.rst, all.py, general_linear.py, schur_algebra.py --- src/sage/algebras/all.py | 1 + src/sage/algebras/schur_algebra.py | 525 +++++++++++++++++++++++++++++ 2 files changed, 526 insertions(+) create mode 100644 src/sage/algebras/schur_algebra.py diff --git a/src/sage/algebras/all.py b/src/sage/algebras/all.py index ec6c162ea2a..c9d162f9ae7 100644 --- a/src/sage/algebras/all.py +++ b/src/sage/algebras/all.py @@ -41,6 +41,7 @@ from iwahori_hecke_algebra import IwahoriHeckeAlgebra from affine_nil_temperley_lieb import AffineNilTemperleyLiebTypeA lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra') +lazy_import('sage.algebras.schur_algebra', ['SchurAlgebra', 'TensorSpace']) lazy_import('sage.algebras.hall_algebra', 'HallAlgebra') diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py new file mode 100644 index 00000000000..eda22773296 --- /dev/null +++ b/src/sage/algebras/schur_algebra.py @@ -0,0 +1,525 @@ + +r""" +Schur algebras for `GL_n` + +This file implements: + +- Schur algebras for `GL_n` over an arbitrary field, + +- The canonical action of the Schur algebra on a tensor power of the standard representation, + +- Using the above to calculate the characters of irreducible `GL_n` modules. + +AUTHORS: + +- Eric Webster (2010-07-01): implement Schur algebra + +- Hugh Thomas (2011-05-08): implement action of Schur algebra and characters of irreducible modules + +REFERENCES: + +J. Green, Polynomial representations of `GL_n`, Springer Verlag. + +""" + +#***************************************************************************** +# Copyright (C) 2010 Eric Webster +# Copyright (C) 2011 Hugh Thomas (hugh.ross.thomas@gmail.com) +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** + + +from sage.categories.all import AlgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.permutation import Permutations +from copy import copy +from sage.rings.ring import CommutativeRing +from sage.rings.integer import Integer +from sage.misc.cachefunc import cached_method +from sage.combinat.sf.sfa import SymmetricFunctionAlgebra +from sage.rings.rational_field import QQ +from sage.combinat.words.word import Word +from sage.combinat.words.words import Words +from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra +from sage.groups.perm_gps.permgroup_named import SymmetricGroup +from sage.combinat.tableau import SemistandardTableaux +from sage.misc.flatten import flatten +from sage.combinat.partition import Partitions, Partition +from sage.matrix.constructor import Matrix + +def SchurAlgebra(n,r,R): + + """ + The Schur algebra for `GL_n` with rank `r` over the + ring `R`. + """ + + if not isinstance(n,(int,Integer)) or n <= 0: + raise ValueError, "n must be a positive integer (n=%s)"%(n) + if not isinstance(r,(int,Integer)) or r < 0: + raise ValueError, "r must be a non-negative integer (r=%s)"%(r) + if not isinstance(R,CommutativeRing): + raise ValueError, "R must be a commutative Ring (R=%s)"%(R) + + return SchurAlgebra_nrR(n,r,R) + +def _schur_I_nr_representatives(n, r, element, index): + + """ + This is an internal function called by schur_representation_indices below. + """ + + if r == 0: + return index + + if len(element) == r: + index.append(copy(element)) + return + + if len(element) == 0: + for i in range(1,n+1): + element.append(i) + _schur_I_nr_representatives(n,r,element,index) + element.pop() + else: + for i in range(element[-1],n+1): + element.append(i) + _schur_I_nr_representatives(n,r,element,index) + element.pop() + + return index + + + +def schur_representative_indices(n, r): + + r""" + This function returns a set which functions as a basis of `S_K(n,r)`. + + More specifically, the basis for `S_K(n,r)` consists of equivalence classes of pairs words of length ``r`` on the alphabet `1\dots n`, + where the equivalence relation is simultaneous permutation of the two words. + We can therefore fix a representative for each equivalence class + in which the entries of the first word + weakly increase, and the entries of the second word + whose corresponding values + in the first word are equal, also weakly increase. + + EXAMPLES:: + + sage: sage.algebras.schur_algebra.schur_representative_indices(2,2) + [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), (word: 22, word: 22)] + + + """ + + basis = [] + I_nr_repr = _schur_I_nr_representatives(n, r, [], []) + for e in I_nr_repr: + j = 0 + k = 0 + I1 = [] + l = len(e) + while k < l: + if e[k] != e[j]: + I2 = [] + if j == 0: + I1 = _schur_I_nr_representatives(n,k-j,[],[]) + else: + I2 = _schur_I_nr_representatives(n,k-j,[],[]) + I = [] + for m1 in range(0,len(I1)): + for m2 in range(0,len(I2)): + I.append(I1[m1]+I2[m2]) + I1 = I + j = k + elif k == l-1: + I2 = [] + k += 1 + if j == 0: + I1 = _schur_I_nr_representatives(n,k-j,[],[]) + else: + I2 = _schur_I_nr_representatives(n,k-j,[],[]) + I = [] + for m1 in range(0,len(I1)): + for m2 in range(0,len(I2)): + I.append(I1[m1]+I2[m2]) + I1 = I + else: + k += 1 + + for v in I1: + basis.append((Word(e),Word(v))) + + return basis + +def schur_representative_from_index(index): + """ + This function simultaneously reorders a pair of words to obtain the + equivalent element + of the distinguished basis of the Schur algebra. + seealso:: :func:`schur_representative_indices` + + INPUT: + + - A 2-ple of words from `Words (range(1,n+1),r)` + + OUTPUT: + + - The corresponding pair of words ordered correctly. + + EXAMPLES:: + + sage: sage.algebras.schur_algebra.schur_representative_from_index((Word([2,1,2,2]),Word([1,3,0,0]))) + (word: 1222, word: 3001) + + + """ + + w = [] + for i in range(0,len(index[0])): + w.append((index[0][i], index[1][i])) + w.sort() + index = [[], []] + for i in range(0, len(w)): + index[0].append(w[i][0]) + index[1].append(w[i][1]) + return tuple(map(Word, index)) + + +class SchurAlgebra_nrR(CombinatorialFreeModule): + + """ + This is the class that implements Schur algebras. + + EXAMPLES:: + + sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(2, 2, ZZ); S + Schur Algebra (2,2) over Integer Ring + + """ + + def __init__(self, n, r, R): + + self._n = n + self._r = r + + CombinatorialFreeModule.__init__(self, R, schur_representative_indices(n,r), category = AlgebrasWithBasis(R)) + + def _repr_(self): + """ + EXAMPLES:: + + sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(4, 4, ZZ) + sage: repr(S) + 'Schur Algebra (4,4) over Integer Ring' + """ + return "Schur Algebra (%s,%s) over %s"%(self._n, self._r, self.base_ring()) + + @cached_method + def one_basis(self): + return None + + def product_on_basis(self, e_ij, e_kl): + r""" + Product of basis elements, as per :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. + + EXAMPLES:: + + sage: S=sage.algebras.schur_algebra.SchurAlgebra(2, 3, QQ) + sage: B=S.basis() + + If we multiply two basis elements `x` and `y`, such that `x[1]` and `y[0]` are not + permutations of each other, the result is zero + + .. link:: + + :: + + sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 2, 2)),Word((1, 1, 2)))] + 0 + + If we multiply a basis element `x` by a basis element which consists of the same tuple repeated twice (on either side), + the result + is either zero (if the previous case applies) or `x` + + .. link:: + + :: + + sage: B[(Word((1, 2, 2)), Word((1, 2, 2)))]*B[(Word((1, 2, 2)), Word((1, 1, 2)))] + B[(word: 122, word: 112)] + + + An arbitrary product, on the other hand, may have multiplicities + + .. link:: + + :: + + sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 1, 2)), Word((1, 2, 2)))] + 2*B[(word: 111, word: 122)] + + """ + + k = e_kl[0] + j = e_ij[1] + + i = e_ij[0] + l = e_kl[1] + + l = sorted(l) + + # Find basis elements (p,q) such that p ~ i and q ~ l + e_pq = [] + for v in self.basis().keys(): + if v[0] == i and sorted(v[1]) == l: + e_pq.append(v) + + b = self.basis() + product = self.zero() + + # Find s in I(n,r) such that (p,s) ~ (i,j) and (s,q) ~ (k,l) + for e in e_pq: + Z_ijklpq = self.base_ring()(0) + for s in Permutations([xx for xx in j]): + if schur_representative_from_index((e[0],s)) == e_ij and schur_representative_from_index((s,e[1])) == e_kl: + Z_ijklpq += self.base_ring()(1) + product += Z_ijklpq*b[e] + + return product + +class TensorSpace(CombinatorialFreeModule): + """ + This is the ``r``-fold tensor product of an ``n``-dimensional free module over ``R``, + equipped with an action of the Schur algebra `S(n,r)` and the + symmetric group `S_r`. + """ + + def __init__(self, n, r, R): + + self._n = n + self._r = r + self._R = R + CombinatorialFreeModule.__init__(self, R, Words(range(1,n+1), r)) + + def _repr_(self): + return "The %s-fold tensor product of a free module of dimension %s over %s"%(self._r, self._n, self.base_ring()) + + def _basis_elt_from_permuted_word(self, v, perm): + """ + return the basis element of self corresponding to applying the permutation perm to a word v + """ + return self.basis()[Word(v).apply_permutation_to_positions(perm)] + + def action_by_perm(self, t, perm): + """ + Apply a permutation to an element of self + + INPUT: + + - ``perm`` is an element of Permutations(self._r) + - ``t`` is an element of self + + OUTPUT: + + - the output is the result of acting by ``perm`` on ``t`` + """ + h=self.module_morphism(self._basis_elt_from_permuted_word, codomain=self) + return h(t, perm) + + def action_by_symmetric_group_algebra(self, t, z): + """ + INPUT: + + - ``t`` -- an element of ``self`` + - ``z`` -- an element of ``SymmetricGroupAlgebra(self._R,self._r)`` + + OUTPUT: + + result of action of ``z`` on ``t``. + """ + S=SymmetricGroupAlgebra(self._R,self._r) + assert z in S + sym_action=S.module_morphism(self.action_by_perm, codomain=self,position=1) + return sym_action(t, z) + + def _monomial_product(self,xi,v): + """ + Result of acting by the basis element ``xi`` of ``S`` on the basis element ``v`` of self. + """ + x=self.zero() + for i in Words(range(1,self._n+1),self._r): + if schur_representative_from_index((i,v))==xi: + x=x+self.basis()[i] + return x + + def action_by_Schur_alg(self,nu,v): + + r""" + returns action of ``nu`` in Schur algebra on ``v`` in ``self``. + """ + + A=SchurAlgebra(self._n,self._r,self._R) + assert nu in A + g=A.module_morphism(self._monomial_product, codomain=self) + action= self.module_morphism(g,codomain=self,position=1) + return action(nu,v) + +def bracket(r,X,S): + r""" + Given ``X`` a set of permutations of ``r`` in cycle notation, + return the sum in the symmetric group algebra + of those permutations, times their sign. + + This implements the notation `\{X\}` from just before (5.3a) of Green. + + EXAMPLES:: + + sage: sage.algebras.schur_algebra.bracket(2,[PermutationGroupElement(()),PermutationGroupElement((1,2))],SymmetricGroupAlgebra(QQ,2)) + () - (1,2) + + """ + t=S.zero() + SG=SymmetricGroup(r) + return sum([x.sign()*S.basis()[SG(x)] for x in X]) + + +def GL_n_irred_character(n,mu,KK): + r""" + This function calculates the character of the irreducible character indexed by ``mu`` of `GL(n)` over the field ``KK``. + + INPUT: + + - ``n`` is a positive integer. + - ``mu`` is a partition of at most ``n`` parts. + - ``KK`` is a field . + + OUTPUT: + + a symmetric function which should be interpreted in ``n`` variables to be meaningful as a character + + EXAMPLES: + + Over `\QQ`, the irreducible character for ``mu`` is the Schur function associated to ``mu``, + plus garbage terms (Schur functions associated to partitions with more than `n` parts) + + :: + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: z = GL_n_irred_character(2, [2], QQ) + sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') + sage: sbasis(z) + s[2] + + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: z = GL_n_irred_character(4, [3, 2], QQ) # long time + sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') # long time + sage: sbasis(z) #long time + -5*s[1, 1, 1, 1, 1] + s[3, 2] + + Over a Galois field, the irreducible character for `\mu` will in general + be smaller. + + In characteristic `p`, for a one-part partition `(r)`, where + `r= a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, after 5.5d] + the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]),\dots,` + which is consistent with the following + + :: + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: GL_n_irred_character(2, [7], GF(3)) # long time + m[4, 3] + m[6, 1] + m[7] + + + """ + mbasis = SymmetricFunctionAlgebra(QQ,basis='monomial') + r=sum(mu) + A=SchurAlgebra(n,r,KK) + M=TensorSpace(n,r,KK) + S=SymmetricGroupAlgebra(KK,r) + + #make ST the superstandard tableau of shape mu + from sage.combinat.tableau import from_shape_and_word + ST=from_shape_and_word(mu, range(1,r+1), order='English') + + #make ell the reading word of the highest weight tableau of shape mu + ell=[] + for i in range(0,len(mu)): + for j in range(0,mu[i]): + ell.append(i+1) + + e=M.basis()[Word(ell)]; #the element e_l + BracC=bracket(r,ST.column_stabilizer(),S) + f=M.action_by_symmetric_group_algebra(e,BracC) + + #[Green, Theorem 5.3b] says that a basis of the Carter-Lusztig module V_\mu is given by taking + #this f, and multiplying by + #all xi_{i,ell} with ell as above and i semistandard. + + carter_lusztig=[] + for i in [Word(flatten(T)) for T in SemistandardTableaux(mu,max_entry=n)]: + y=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],e) + carter_lusztig.append(y.to_vector()) + + #Therefore, we now have carter_lusztig as a list giving the basis of `V_\mu` + + #We want to think of expressing this character as a sum of monomial + #symmetric functions. + + #We will determine a basis element for each m_\lambda in the + #character, and we want to keep track of them by \lambda. + + #That means that we only want to pick out the basis elements above for + #those semistandard words whose content is a partition. + + contents=Partitions(r,max_length=n).list() #all partitions of r, length at most n + + # JJ will consist of a list for each element of `contents`, + # recording the list + # of semistandard tableaux words with that content + + # graded_basis will consist of the a corresponding basis element + + + graded_basis=[] + JJ=[] + for i in range(0,len(contents)): + graded_basis.append([]) + JJ.append([]) + for i in [Word(flatten(T),range(1,n+1))for T in SemistandardTableaux(mu,max_entry=n)]: + con=i.evaluation() + if all([ con[j+1] <= con[j] for j in range(0,len(con)-1)]): + #don't test whether con is in Partitions, because con could + #have trailing zeros + JJ[contents.index(Partition(con))].append(i) + x=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],f) + graded_basis[contents.index(Partition(con))].append(x.to_vector()) + + #There is an inner product on the Carter-Lusztig module V_\mu; its + #maximal submodule is exactly the kernel of the inner product. + + #Now, for each possible partition content, we look at the graded piece of + #that degree, and we record how these elements pair with each of the + #elements of carter_lusztig. + + #The kernel of this pairing is the part of this graded piece which is + #not in the irreducible module for \mu. + + length=len(carter_lusztig) + + Phi=mbasis.zero() + for aa in range(0,len(contents)): + Mat=[] + for kk in range(0,len(JJ[aa])): + temp=[] + for j in range(0,length): + temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) + Mat.append(temp) + Angle=Matrix(Mat) + Phi=Phi+(len(JJ[aa])-Angle.kernel().rank())*mbasis(contents[aa]) + return Phi + From ad478d3d9ca70f98316243c3cb0800c7a9210ca7 Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Fri, 24 Apr 2015 10:42:01 +0200 Subject: [PATCH 501/665] #17682: change to loadable_module_extension --- src/sage/misc/cython.py | 10 +++++----- src/sage/misc/sageinspect.py | 16 ++++++---------- src/sage_setup/clean.py | 8 ++++---- src/sage_setup/find.py | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 4b7b2b61dcd..760487ed8cc 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -378,13 +378,13 @@ def cython(filename, verbose=False, compile_message=False, # There is already a module here. Maybe we do not have to rebuild? # Find the name. if use_cache: - from sage.misc.sageinspect import shared_lib_extension - prev_so = [F for F in os.listdir(build_dir) if F.endswith(shared_lib_extension())] + from sage.misc.sageinspect import loadable_module_extension + prev_so = [F for F in os.listdir(build_dir) if F.endswith(loadable_module_extension())] if len(prev_so) > 0: prev_so = prev_so[0] # should have length 1 because of deletes below if os.path.getmtime(filename) <= os.path.getmtime('%s/%s'%(build_dir, prev_so)): # We do not have to rebuild. - return prev_so[:-len(shared_lib_extension())], build_dir + return prev_so[:-len(loadable_module_extension())], build_dir else: os.makedirs(build_dir) for F in os.listdir(build_dir): @@ -544,8 +544,8 @@ def cython(filename, verbose=False, compile_message=False, if create_local_so_file: # Copy from lib directory into local directory - from sage.misc.sageinspect import shared_lib_extension - cmd = 'cp %s/%s%s %s'%(build_dir, name, shared_lib_extension(), os.path.abspath(os.curdir)) + from sage.misc.sageinspect import loadable_module_extension + cmd = 'cp %s/%s%s %s'%(build_dir, name, loadable_module_extension(), os.path.abspath(os.curdir)) if os.system(cmd): raise RuntimeError("Error making local copy of shared object library for {}".format(filename)) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 70542f70938..889ec42d168 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -121,19 +121,15 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return EMBEDDED_MODE = False from sage.env import SAGE_SRC -def shared_lib_extension(): +def loadable_module_extension(): r""" - Return the filename extension of shared libraries, including the dot. + Return the filename extension of loadable modules, including the dot. It is '.dll' on cygwin, '.so' otherwise. EXAMPLES:: - sage: from site import getsitepackages - sage: site_packages = getsitepackages()[0] - sage: from sage_setup.find import installed_files_by_module - sage: files_by_module = installed_files_by_module(site_packages) - sage: from sage.misc.sageinspect import shared_lib_extension - sage: files_by_module['sage.structure.sage_object'].pop().endswith(shared_lib_extension()) + sage: from sage.misc.sageinspect import loadable_module_extension + sage: sage.structure.sage_object.__file__.endswith(loadable_module_extension()) True """ import sys @@ -1196,8 +1192,8 @@ def sage_getfile(obj): # No go? fall back to inspect. sourcefile = inspect.getabsfile(obj) - if sourcefile.endswith(shared_lib_extension()): - return sourcefile[:-len(shared_lib_extension())]+os.path.extsep+'pyx' + if sourcefile.endswith(loadable_module_extension()): + return sourcefile[:-len(loadable_module_extension())]+os.path.extsep+'pyx' return sourcefile def sage_getargspec(obj): diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index f56f60e5b51..76a8ae1e89f 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -80,14 +80,14 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module extension modules:: sage: stale_iter = _find_stale_files(SAGE_LIB, python_packages, python_modules, []) - sage: from sage.misc.sageinspect import shared_lib_extension + sage: from sage.misc.sageinspect import loadable_module_extension sage: for f in stale_iter: - ....: if f.endswith(shared_lib_extension()): continue + ....: if f.endswith(loadable_module_extension()): continue ....: print('Found stale file: ' + f) """ PYMOD_EXTS = (os.path.extsep + 'py', os.path.extsep + 'pyc') - from sage.misc.sageinspect import shared_lib_extension - CEXTMOD_EXTS = (shared_lib_extension(),) + from sage.misc.sageinspect import loadable_module_extension + CEXTMOD_EXTS = (loadable_module_extension(),) INIT_FILES= map(lambda x: '__init__' + x, PYMOD_EXTS) module_files = installed_files_by_module(site_packages, ['sage', 'sage_setup']) diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index 8aff82badfb..e23fa915921 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -100,9 +100,9 @@ def installed_files_by_module(site_packages, modules=('sage',)): sage: from site import getsitepackages sage: site_packages = getsitepackages()[0] sage: files_by_module = installed_files_by_module(site_packages) - sage: from sage.misc.sageinspect import shared_lib_extension + sage: from sage.misc.sageinspect import loadable_module_extension sage: files_by_module['sage.structure.sage_object'] == \ - ....: {'sage/structure/sage_object' + shared_lib_extension()} + ....: {'sage/structure/sage_object' + loadable_module_extension()} True sage: sorted(files_by_module['sage.structure']) ['sage/structure/__init__.py', 'sage/structure/__init__.pyc'] From a051cedd863487bb61b317b4b1a537607ff481e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 24 Apr 2015 10:51:01 +0200 Subject: [PATCH 502/665] trac #9123 cleaning the file --- src/doc/en/reference/algebras/index.rst | 1 + src/sage/algebras/schur_algebra.py | 492 +++++++++++++----------- 2 files changed, 263 insertions(+), 230 deletions(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 4e5792d031b..467b1be19f1 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -31,6 +31,7 @@ Algebras sage/algebras/iwahori_hecke_algebra sage/algebras/nil_coxeter_algebra sage/algebras/affine_nil_temperley_lieb + sage/algebras/schur_algebra sage/algebras/hall_algebra sage/algebras/jordan_algebra diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index eda22773296..113a62456a6 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -1,12 +1,12 @@ - r""" Schur algebras for `GL_n` -This file implements: +This file implements: - Schur algebras for `GL_n` over an arbitrary field, -- The canonical action of the Schur algebra on a tensor power of the standard representation, +- The canonical action of the Schur algebra on a tensor power of the standard + representation, - Using the above to calculate the characters of irreducible `GL_n` modules. @@ -14,14 +14,13 @@ - Eric Webster (2010-07-01): implement Schur algebra -- Hugh Thomas (2011-05-08): implement action of Schur algebra and characters of irreducible modules +- Hugh Thomas (2011-05-08): implement action of Schur algebra and characters + of irreducible modules REFERENCES: -J. Green, Polynomial representations of `GL_n`, Springer Verlag. - +.. [GreenPoly] J. Green, Polynomial representations of `GL_n`, Springer Verlag. """ - #***************************************************************************** # Copyright (C) 2010 Eric Webster # Copyright (C) 2011 Hugh Thomas (hugh.ross.thomas@gmail.com) @@ -38,7 +37,7 @@ from sage.rings.ring import CommutativeRing from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method -from sage.combinat.sf.sfa import SymmetricFunctionAlgebra +from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.rational_field import QQ from sage.combinat.words.word import Word from sage.combinat.words.words import Words @@ -49,28 +48,31 @@ from sage.combinat.partition import Partitions, Partition from sage.matrix.constructor import Matrix -def SchurAlgebra(n,r,R): +def SchurAlgebra(n, r, R): """ The Schur algebra for `GL_n` with rank `r` over the ring `R`. + + EXAMPLES:: + + sage: SchurAlgebra(6,3,QQ) + Schur Algebra (6,3) over Rational Field """ + if not isinstance(n, (int, Integer)) or n <= 0: + raise ValueError("n must be a positive integer (n=%s)" % (n)) + if not isinstance(r, (int, Integer)) or r < 0: + raise ValueError("r must be a non-negative integer (r=%s)" % (r)) + if not isinstance(R, CommutativeRing): + raise ValueError("R must be a commutative Ring (R=%s)" % (R)) - if not isinstance(n,(int,Integer)) or n <= 0: - raise ValueError, "n must be a positive integer (n=%s)"%(n) - if not isinstance(r,(int,Integer)) or r < 0: - raise ValueError, "r must be a non-negative integer (r=%s)"%(r) - if not isinstance(R,CommutativeRing): - raise ValueError, "R must be a commutative Ring (R=%s)"%(R) + return SchurAlgebra_nrR(n, r, R) - return SchurAlgebra_nrR(n,r,R) def _schur_I_nr_representatives(n, r, element, index): - """ This is an internal function called by schur_representation_indices below. """ - if r == 0: return index @@ -79,41 +81,40 @@ def _schur_I_nr_representatives(n, r, element, index): return if len(element) == 0: - for i in range(1,n+1): + for i in range(1, n + 1): element.append(i) - _schur_I_nr_representatives(n,r,element,index) + _schur_I_nr_representatives(n, r, element, index) element.pop() else: - for i in range(element[-1],n+1): + for i in range(element[-1], n + 1): element.append(i) - _schur_I_nr_representatives(n,r,element,index) + _schur_I_nr_representatives(n, r, element, index) element.pop() return index - def schur_representative_indices(n, r): - r""" - This function returns a set which functions as a basis of `S_K(n,r)`. - - More specifically, the basis for `S_K(n,r)` consists of equivalence classes of pairs words of length ``r`` on the alphabet `1\dots n`, - where the equivalence relation is simultaneous permutation of the two words. - We can therefore fix a representative for each equivalence class - in which the entries of the first word - weakly increase, and the entries of the second word - whose corresponding values - in the first word are equal, also weakly increase. + Return a set which functions as a basis of `S_K(n,r)`. + + More specifically, the basis for `S_K(n,r)` consists of + equivalence classes of pairs words of length ``r`` on the alphabet + `1\dots n`, where the equivalence relation is simultaneous + permutation of the two words. We can therefore fix a + representative for each equivalence class in which the entries of + the first word weakly increase, and the entries of the second word + whose corresponding values in the first word are equal, also + weakly increase. EXAMPLES:: sage: sage.algebras.schur_algebra.schur_representative_indices(2,2) - [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), (word: 22, word: 22)] - - + [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), + (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), + (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), + (word: 22, word: 22)] """ - basis = [] I_nr_repr = _schur_I_nr_representatives(n, r, [], []) for e in I_nr_repr: @@ -125,45 +126,48 @@ def schur_representative_indices(n, r): if e[k] != e[j]: I2 = [] if j == 0: - I1 = _schur_I_nr_representatives(n,k-j,[],[]) + I1 = _schur_I_nr_representatives(n, k - j, [], []) else: - I2 = _schur_I_nr_representatives(n,k-j,[],[]) + I2 = _schur_I_nr_representatives(n, k - j, [], []) I = [] - for m1 in range(0,len(I1)): - for m2 in range(0,len(I2)): - I.append(I1[m1]+I2[m2]) + for m1 in range(len(I1)): + for m2 in range(len(I2)): + I.append(I1[m1] + I2[m2]) I1 = I j = k - elif k == l-1: + elif k == l - 1: I2 = [] k += 1 if j == 0: - I1 = _schur_I_nr_representatives(n,k-j,[],[]) + I1 = _schur_I_nr_representatives(n, k - j, [], []) else: - I2 = _schur_I_nr_representatives(n,k-j,[],[]) + I2 = _schur_I_nr_representatives(n, k - j, [], []) I = [] - for m1 in range(0,len(I1)): - for m2 in range(0,len(I2)): - I.append(I1[m1]+I2[m2]) + for m1 in range(len(I1)): + for m2 in range(len(I2)): + I.append(I1[m1] + I2[m2]) I1 = I else: k += 1 for v in I1: - basis.append((Word(e),Word(v))) + basis.append((Word(e), Word(v))) return basis + def schur_representative_from_index(index): """ - This function simultaneously reorders a pair of words to obtain the - equivalent element - of the distinguished basis of the Schur algebra. - seealso:: :func:`schur_representative_indices` + Simultaneously reorder a pair of words to obtain the equivalent + element of the distinguished basis of the Schur algebra. + + .. SEEALSO:: + + :func:`schur_representative_indices` INPUT: - - A 2-ple of words from `Words (range(1,n+1),r)` + - A pair of words from `Words (range(1,n+1),r)` OUTPUT: @@ -173,97 +177,101 @@ def schur_representative_from_index(index): sage: sage.algebras.schur_algebra.schur_representative_from_index((Word([2,1,2,2]),Word([1,3,0,0]))) (word: 1222, word: 3001) - - """ - w = [] - for i in range(0,len(index[0])): + for i in range(len(index[0])): w.append((index[0][i], index[1][i])) w.sort() index = [[], []] - for i in range(0, len(w)): + for i in range(len(w)): index[0].append(w[i][0]) index[1].append(w[i][1]) return tuple(map(Word, index)) class SchurAlgebra_nrR(CombinatorialFreeModule): - """ This is the class that implements Schur algebras. EXAMPLES:: - sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(2, 2, ZZ); S + sage: from sage.algebras.all import SchurAlgebra + sage: S = SchurAlgebra(2, 2, ZZ); S # indirect doctest Schur Algebra (2,2) over Integer Ring - """ - def __init__(self, n, r, R): self._n = n self._r = r - CombinatorialFreeModule.__init__(self, R, schur_representative_indices(n,r), category = AlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, R, + schur_representative_indices(n, r), + category=AlgebrasWithBasis(R)) def _repr_(self): """ + Return the string representation of ``self``. + EXAMPLES:: - sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(4, 4, ZZ) + sage: from sage.algebras.all import SchurAlgebra + sage: S = SchurAlgebra(4, 4, ZZ) # indirect doctest sage: repr(S) 'Schur Algebra (4,4) over Integer Ring' """ - return "Schur Algebra (%s,%s) over %s"%(self._n, self._r, self.base_ring()) + return "Schur Algebra (%s,%s) over %s" % (self._n, self._r, + self.base_ring()) - @cached_method + @cached_method def one_basis(self): + """ + Return the index of the one of the algebra. + + THIS IS WRONG ! + + EXAMPLES:: + + sage: from sage.algebras.all import SchurAlgebra + sage: SchurAlgebra(4, 4, ZZ).one() # indirect doctest + B[None] + """ return None def product_on_basis(self, e_ij, e_kl): r""" - Product of basis elements, as per :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. + Return the product of basis elements. EXAMPLES:: - sage: S=sage.algebras.schur_algebra.SchurAlgebra(2, 3, QQ) - sage: B=S.basis() - - If we multiply two basis elements `x` and `y`, such that `x[1]` and `y[0]` are not - permutations of each other, the result is zero + sage: from sage.algebras.all import SchurAlgebra + sage: S = SchurAlgebra(2, 3, QQ) + sage: B = S.basis() - .. link:: + If we multiply two basis elements `x` and `y`, such that + `x[1]` and `y[0]` are not permutations of each other, the + result is zero :: - :: - - sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 2, 2)),Word((1, 1, 2)))] + sage: x = B[(Word((1, 1, 1)), Word((1, 1, 2)))] + sage: y = B[(Word((1, 2, 2)),Word((1, 1, 2)))] + sage: x * y 0 - - If we multiply a basis element `x` by a basis element which consists of the same tuple repeated twice (on either side), - the result - is either zero (if the previous case applies) or `x` - - .. link:: - :: + If we multiply a basis element `x` by a basis element which + consists of the same tuple repeated twice (on either side), + the result is either zero (if the previous case applies) or `x` :: - sage: B[(Word((1, 2, 2)), Word((1, 2, 2)))]*B[(Word((1, 2, 2)), Word((1, 1, 2)))] + sage: ww = B[(Word((1, 2, 2)), Word((1, 2, 2)))] + sage: x = B[(Word((1, 2, 2)), Word((1, 1, 2)))] + sage: ww * x B[(word: 122, word: 112)] + An arbitrary product, on the other hand, may have multiplicities:: - An arbitrary product, on the other hand, may have multiplicities - - .. link:: - - :: - - sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 1, 2)), Word((1, 2, 2)))] + sage: x = B[(Word((1, 1, 1)), Word((1, 1, 2)))] + sage: y = B[(Word((1, 1, 2)), Word((1, 2, 2)))] + sage: x * y 2*B[(word: 111, word: 122)] - """ - - k = e_kl[0] j = e_ij[1] i = e_ij[0] @@ -284,53 +292,77 @@ def product_on_basis(self, e_ij, e_kl): for e in e_pq: Z_ijklpq = self.base_ring()(0) for s in Permutations([xx for xx in j]): - if schur_representative_from_index((e[0],s)) == e_ij and schur_representative_from_index((s,e[1])) == e_kl: - Z_ijklpq += self.base_ring()(1) - product += Z_ijklpq*b[e] + if (schur_representative_from_index((e[0], s)) == e_ij + and schur_representative_from_index((s, e[1])) == e_kl): + Z_ijklpq += self.base_ring().one() + product += Z_ijklpq * b[e] + + return product - return product class TensorSpace(CombinatorialFreeModule): """ - This is the ``r``-fold tensor product of an ``n``-dimensional free module over ``R``, - equipped with an action of the Schur algebra `S(n,r)` and the - symmetric group `S_r`. - """ + This is the ``r``-fold tensor product of an ``n``-dimensional free + module over ``R``, equipped with an action of the Schur algebra + `S(n,r)` and the symmetric group `S_r`. + + EXAMPLES:: + sage: from sage.algebras.all import TensorSpace + sage: TensorSpace(2, 3, QQ) + The 3-fold tensor product of a free module of dimension 2 + over Rational Field + """ def __init__(self, n, r, R): self._n = n self._r = r self._R = R - CombinatorialFreeModule.__init__(self, R, Words(range(1,n+1), r)) + CombinatorialFreeModule.__init__(self, R, Words(range(1, n + 1), r)) def _repr_(self): - return "The %s-fold tensor product of a free module of dimension %s over %s"%(self._r, self._n, self.base_ring()) + """ + Return the string representation of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.all import TensorSpace + sage: TensorSpace(2, 3, QQ) + The 3-fold tensor product of a free module of dimension 2 + over Rational Field + """ + msg = "The {}-fold tensor product of a free module of dimension {}" + msg += " over {}" + return msg.format(self._r, self._n, self.base_ring()) def _basis_elt_from_permuted_word(self, v, perm): """ - return the basis element of self corresponding to applying the permutation perm to a word v + Return the basis element of ``self`` corresponding to applying + the permutation perm to a word v. """ return self.basis()[Word(v).apply_permutation_to_positions(perm)] def action_by_perm(self, t, perm): """ - Apply a permutation to an element of self + Apply a permutation to an element `t` of ``self`` INPUT: - - ``perm`` is an element of Permutations(self._r) - - ``t`` is an element of self + - ``perm`` -- an element of Permutations(self._r) + - ``t`` -- an element of ``self`` OUTPUT: - the output is the result of acting by ``perm`` on ``t`` """ - h=self.module_morphism(self._basis_elt_from_permuted_word, codomain=self) + h = self.module_morphism(self._basis_elt_from_permuted_word, + codomain=self) return h(t, perm) def action_by_symmetric_group_algebra(self, t, z): """ + Return the action by an element of the symmetric group algebra. + INPUT: - ``t`` -- an element of ``self`` @@ -338,188 +370,188 @@ def action_by_symmetric_group_algebra(self, t, z): OUTPUT: - result of action of ``z`` on ``t``. + result of action of ``z`` on ``t``. """ - S=SymmetricGroupAlgebra(self._R,self._r) + S = SymmetricGroupAlgebra(self._R, self._r) assert z in S - sym_action=S.module_morphism(self.action_by_perm, codomain=self,position=1) + sym_action = S.module_morphism(self.action_by_perm, codomain=self, + position=1) return sym_action(t, z) - def _monomial_product(self,xi,v): + def _monomial_product(self, xi, v): """ - Result of acting by the basis element ``xi`` of ``S`` on the basis element ``v`` of self. + Result of acting by the basis element ``xi`` of ``S`` on the + basis element ``v`` of ``self``. """ - x=self.zero() - for i in Words(range(1,self._n+1),self._r): - if schur_representative_from_index((i,v))==xi: - x=x+self.basis()[i] + x = self.zero() + for i in Words(range(1, self._n + 1), self._r): + if schur_representative_from_index((i, v)) == xi: + x += self.basis()[i] return x - def action_by_Schur_alg(self,nu,v): - + def action_by_Schur_alg(self, nu, v): r""" - returns action of ``nu`` in Schur algebra on ``v`` in ``self``. + Return the action of ``nu`` in Schur algebra on ``v`` in ``self``. """ - - A=SchurAlgebra(self._n,self._r,self._R) + A = SchurAlgebra(self._n, self._r, self._R) assert nu in A - g=A.module_morphism(self._monomial_product, codomain=self) - action= self.module_morphism(g,codomain=self,position=1) - return action(nu,v) + g = A.module_morphism(self._monomial_product, codomain=self) + action = self.module_morphism(g, codomain=self, position=1) + return action(nu, v) + -def bracket(r,X,S): +def bracket(r, X, S): r""" - Given ``X`` a set of permutations of ``r`` in cycle notation, + Given ``X`` a set of permutations of ``r`` in cycle notation, return the sum in the symmetric group algebra of those permutations, times their sign. - This implements the notation `\{X\}` from just before (5.3a) of Green. + This implements the notation `\{X\}` from just before (5.3a) of Green. EXAMPLES:: - sage: sage.algebras.schur_algebra.bracket(2,[PermutationGroupElement(()),PermutationGroupElement((1,2))],SymmetricGroupAlgebra(QQ,2)) + sage: P = PermutationGroupElement + sage: S2 = SymmetricGroupAlgebra(QQ,2) + sage: sage.algebras.schur_algebra.bracket(2,[P(()),P((1,2))], S2) () - (1,2) - """ - t=S.zero() - SG=SymmetricGroup(r) - return sum([x.sign()*S.basis()[SG(x)] for x in X]) + SG = SymmetricGroup(r) + return sum([x.sign() * S.basis()[SG(x)] for x in X]) -def GL_n_irred_character(n,mu,KK): +def GL_n_irred_character(n, mu, KK): r""" - This function calculates the character of the irreducible character indexed by ``mu`` of `GL(n)` over the field ``KK``. - + Return the character of the irreducible module indexed by ``mu`` + of `GL(n)` over the field ``KK``. + INPUT: - - ``n`` is a positive integer. - - ``mu`` is a partition of at most ``n`` parts. - - ``KK`` is a field . - + - ``n`` -- a positive integer. + - ``mu`` -- a partition of at most ``n`` parts. + - ``KK`` -- a field. + OUTPUT: - a symmetric function which should be interpreted in ``n`` variables to be meaningful as a character + a symmetric function which should be interpreted in ``n`` + variables to be meaningful as a character EXAMPLES: - Over `\QQ`, the irreducible character for ``mu`` is the Schur function associated to ``mu``, - plus garbage terms (Schur functions associated to partitions with more than `n` parts) - - :: - - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: z = GL_n_irred_character(2, [2], QQ) - sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') - sage: sbasis(z) - s[2] - - - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: z = GL_n_irred_character(4, [3, 2], QQ) # long time - sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') # long time - sage: sbasis(z) #long time - -5*s[1, 1, 1, 1, 1] + s[3, 2] - - Over a Galois field, the irreducible character for `\mu` will in general - be smaller. - - In characteristic `p`, for a one-part partition `(r)`, where - `r= a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, after 5.5d] - the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]),\dots,` - which is consistent with the following - - :: - - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: GL_n_irred_character(2, [7], GF(3)) # long time - m[4, 3] + m[6, 1] + m[7] - - + Over `\QQ`, the irreducible character for ``mu`` is the Schur + function associated to ``mu``, plus garbage terms (Schur + functions associated to partitions with more than `n` parts) :: + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: z = GL_n_irred_character(2, [2], QQ) + sage: sbasis = SymmetricFunctions(QQ).s() + sage: sbasis(z) + s[2] + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: z = GL_n_irred_character(4, [3, 2], QQ) # long time + sage: sbasis = SymmetricFunctions(QQ).s() # long time + sage: sbasis(z) # long time + -5*s[1, 1, 1, 1, 1] + s[3, 2] + + Over a Galois field, the irreducible character for `\mu` will + in general be smaller. + + In characteristic `p`, for a one-part partition `(r)`, where + `r= a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, + after 5.5d] the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] + ( pbasis[p^2]),\dots,` which is consistent with the following :: + + sage: from sage.algebras.schur_algebra import GL_n_irred_character + sage: GL_n_irred_character(2, [7], GF(3)) # long time + m[4, 3] + m[6, 1] + m[7] """ - mbasis = SymmetricFunctionAlgebra(QQ,basis='monomial') - r=sum(mu) - A=SchurAlgebra(n,r,KK) - M=TensorSpace(n,r,KK) - S=SymmetricGroupAlgebra(KK,r) + mbasis = SymmetricFunctions(QQ).m() + r = sum(mu) + A = SchurAlgebra(n, r, KK) + M = TensorSpace(n, r, KK) + S = SymmetricGroupAlgebra(KK, r) #make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word - ST=from_shape_and_word(mu, range(1,r+1), order='English') + ST = from_shape_and_word(mu, range(1, r + 1), convention='English') #make ell the reading word of the highest weight tableau of shape mu - ell=[] - for i in range(0,len(mu)): - for j in range(0,mu[i]): - ell.append(i+1) - - e=M.basis()[Word(ell)]; #the element e_l - BracC=bracket(r,ST.column_stabilizer(),S) - f=M.action_by_symmetric_group_algebra(e,BracC) - - #[Green, Theorem 5.3b] says that a basis of the Carter-Lusztig module V_\mu is given by taking - #this f, and multiplying by - #all xi_{i,ell} with ell as above and i semistandard. - - carter_lusztig=[] - for i in [Word(flatten(T)) for T in SemistandardTableaux(mu,max_entry=n)]: - y=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],e) + ell = [] + for i in range(len(mu)): + for j in range(mu[i]): + ell.append(i + 1) + + e = M.basis()[Word(ell)] # the element e_l + BracC = bracket(r, ST.column_stabilizer(), S) + f = M.action_by_symmetric_group_algebra(e, BracC) + + # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig + # module V_\mu is given by taking this f, and multiplying by all + # xi_{i,ell} with ell as above and i semistandard. + + carter_lusztig = [] + for i in [Word(flatten(T)) for T in SemistandardTableaux(mu, max_entry=n)]: + schur_rep = schur_representative_from_index((i, Word(ell))) + y = M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) - #Therefore, we now have carter_lusztig as a list giving the basis of `V_\mu` + #Therefore, we now have carter_lusztig as a list giving the basis + #of `V_\mu` #We want to think of expressing this character as a sum of monomial - #symmetric functions. + #symmetric functions. - #We will determine a basis element for each m_\lambda in the + #We will determine a basis element for each m_\lambda in the #character, and we want to keep track of them by \lambda. - #That means that we only want to pick out the basis elements above for - #those semistandard words whose content is a partition. + #That means that we only want to pick out the basis elements above for + #those semistandard words whose content is a partition. - contents=Partitions(r,max_length=n).list() #all partitions of r, length at most n + contents = Partitions(r, max_length=n).list() + # all partitions of r, length at most n - # JJ will consist of a list for each element of `contents`, + # JJ will consist of a list for each element of `contents`, # recording the list # of semistandard tableaux words with that content # graded_basis will consist of the a corresponding basis element - - graded_basis=[] - JJ=[] - for i in range(0,len(contents)): + graded_basis = [] + JJ = [] + for i in range(len(contents)): graded_basis.append([]) JJ.append([]) - for i in [Word(flatten(T),range(1,n+1))for T in SemistandardTableaux(mu,max_entry=n)]: - con=i.evaluation() - if all([ con[j+1] <= con[j] for j in range(0,len(con)-1)]): - #don't test whether con is in Partitions, because con could - #have trailing zeros + for i in [Word(flatten(T), range(1, n + 1)) + for T in SemistandardTableaux(mu, max_entry=n)]: + con = i.evaluation() + if all([con[j + 1] <= con[j] for j in range(len(con) - 1)]): + #don't test whether con is in Partitions, because con could + #have trailing zeros JJ[contents.index(Partition(con))].append(i) - x=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],f) + schur_rep = schur_representative_from_index((i, Word(ell))) + x = M.action_by_Schur_alg(A.basis()[schur_rep], f) graded_basis[contents.index(Partition(con))].append(x.to_vector()) - #There is an inner product on the Carter-Lusztig module V_\mu; its - #maximal submodule is exactly the kernel of the inner product. + #There is an inner product on the Carter-Lusztig module V_\mu; its + #maximal submodule is exactly the kernel of the inner product. #Now, for each possible partition content, we look at the graded piece of #that degree, and we record how these elements pair with each of the - #elements of carter_lusztig. - + #elements of carter_lusztig. + #The kernel of this pairing is the part of this graded piece which is - #not in the irreducible module for \mu. + #not in the irreducible module for \mu. - length=len(carter_lusztig) + length = len(carter_lusztig) - Phi=mbasis.zero() - for aa in range(0,len(contents)): - Mat=[] - for kk in range(0,len(JJ[aa])): - temp=[] - for j in range(0,length): + Phi = mbasis.zero() + for aa in range(len(contents)): + Mat = [] + for kk in range(len(JJ[aa])): + temp = [] + for j in range(length): temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) Mat.append(temp) - Angle=Matrix(Mat) - Phi=Phi+(len(JJ[aa])-Angle.kernel().rank())*mbasis(contents[aa]) + Angle = Matrix(Mat) + Phi += (len(JJ[aa]) - Angle.kernel().rank()) * mbasis(contents[aa]) return Phi - From 0c44982418b96b37731814a0e949471b61270084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 11:20:24 +0200 Subject: [PATCH 503/665] 17696: use is_identity_decomposition_into_orthogonal_idempotents in the examples --- .../finite_dimensional_algebras_with_basis.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 0889693145f..24afbcfdcbc 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -485,7 +485,8 @@ def orthogonal_idempotents_central_mod_rad(self): sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) - sage: orth = A.orthogonal_idempotents_central_mod_rad(); orth + sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: idempotents [-1/2*B[8] + 1/2*B[4], 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], @@ -495,27 +496,28 @@ def orthogonal_idempotents_central_mod_rad(self): 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - 1/4*B[7], -B[0] + 1/2*B[3] + 1/2*B[9], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] - sage: sum(orth) == 1 + sage: sum(idempotents) == 1 + True + sage: all(e*e == e for e in idempotents) True - sage: all(e*e == e for e in orth) + sage: all(e*f == 0 and f*e == 0 for e in idempotents for f in idempotents if e != f) True - sage: all(e*f == 0 and f*e == 0 for e in orth for f in orth if e != f) + + This is best tested with:: + + sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True - We construct orthogonal idempotents of the algebra of the `0`-Hecke - monoid:: + We construct orthogonal idempotents of the algebra of the + `0`-Hecke monoid:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: W = WeylGroup(['A', 3]); W.rename("W") sage: ambient_monoid = FiniteSetMaps(W, action="right") sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) sage: A = AutomaticSemigroup(pi, one=ambient_monoid.one()).algebra(QQ) - sage: orth = A.orthogonal_idempotents_central_mod_rad() - sage: sum(orth) == 1 - True - sage: all(e*e == e for e in orth) - True - sage: all(e*f == 0 and f*e == 0 for e in orth for f in orth if e!= f) + sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True """ one = self.one() From ce20f4a20cddde7f2287fd6c9b5c692ab0fa15ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 24 Apr 2015 11:26:33 +0200 Subject: [PATCH 504/665] trac #9123 simplify the logic a bit --- src/sage/algebras/schur_algebra.py | 59 ++++++++++++++++-------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 113a62456a6..6e1486abb85 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -34,7 +34,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.permutation import Permutations from copy import copy -from sage.rings.ring import CommutativeRing +from sage.categories.rings import Rings from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method from sage.combinat.sf.sf import SymmetricFunctions @@ -49,29 +49,9 @@ from sage.matrix.constructor import Matrix -def SchurAlgebra(n, r, R): - """ - The Schur algebra for `GL_n` with rank `r` over the - ring `R`. - - EXAMPLES:: - - sage: SchurAlgebra(6,3,QQ) - Schur Algebra (6,3) over Rational Field - """ - if not isinstance(n, (int, Integer)) or n <= 0: - raise ValueError("n must be a positive integer (n=%s)" % (n)) - if not isinstance(r, (int, Integer)) or r < 0: - raise ValueError("r must be a non-negative integer (r=%s)" % (r)) - if not isinstance(R, CommutativeRing): - raise ValueError("R must be a commutative Ring (R=%s)" % (R)) - - return SchurAlgebra_nrR(n, r, R) - - def _schur_I_nr_representatives(n, r, element, index): """ - This is an internal function called by schur_representation_indices below. + Internal function called by :func:`schur_representation_indices`. """ if r == 0: return index @@ -109,7 +89,8 @@ def schur_representative_indices(n, r): EXAMPLES:: - sage: sage.algebras.schur_algebra.schur_representative_indices(2,2) + sage: from sage.algebras.schur_algebra import schur_representative_indices + sage: schur_representative_indices(2,2) [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), @@ -175,7 +156,10 @@ def schur_representative_from_index(index): EXAMPLES:: - sage: sage.algebras.schur_algebra.schur_representative_from_index((Word([2,1,2,2]),Word([1,3,0,0]))) + sage: from sage.algebras.schur_algebra import schur_representative_from_index + sage: w1 = Word([2,1,2,2]) + sage: w2 = Word([1,3,0,0]) + sage: schur_representative_from_index((w1,w2)) (word: 1222, word: 3001) """ w = [] @@ -189,17 +173,38 @@ def schur_representative_from_index(index): return tuple(map(Word, index)) -class SchurAlgebra_nrR(CombinatorialFreeModule): +class SchurAlgebra(CombinatorialFreeModule): """ This is the class that implements Schur algebras. EXAMPLES:: sage: from sage.algebras.all import SchurAlgebra - sage: S = SchurAlgebra(2, 2, ZZ); S # indirect doctest + sage: S = SchurAlgebra(2, 2, ZZ); S Schur Algebra (2,2) over Integer Ring + + TESTS:: + + sage: SchurAlgebra(-2, 2, ZZ) + Traceback (most recent call last): + ... + ValueError: n must be a positive integer (n=-2) + sage: SchurAlgebra(2, -2, ZZ) + Traceback (most recent call last): + ... + ValueError: r must be a non-negative integer (r=-2) + sage: SchurAlgebra(2, 2, 'niet') + Traceback (most recent call last): + ... + ValueError: R must be a commutative Ring (R=niet) """ def __init__(self, n, r, R): + if not isinstance(n, (int, Integer)) or n <= 0: + raise ValueError("n must be a positive integer (n=%s)" % (n)) + if not isinstance(r, (int, Integer)) or r < 0: + raise ValueError("r must be a non-negative integer (r=%s)" % (r)) + if not R in Rings.Commutative(): + raise ValueError("R must be a commutative Ring (R=%s)" % (R)) self._n = n self._r = r @@ -553,5 +558,5 @@ def GL_n_irred_character(n, mu, KK): temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) Mat.append(temp) Angle = Matrix(Mat) - Phi += (len(JJ[aa]) - Angle.kernel().rank()) * mbasis(contents[aa]) + Phi += (len(JJ[aa]) - Angle.nullity()) * mbasis(contents[aa]) return Phi From cba7c8d1adcad21ace893b5827777348c2e486ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 12:38:08 +0200 Subject: [PATCH 505/665] 17696: factored out of the examples a basic implementation of the 0-Hecke monoid --- src/doc/en/reference/monoids/index.rst | 1 + .../finite_dimensional_algebras_with_basis.py | 26 ++++++------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/doc/en/reference/monoids/index.rst b/src/doc/en/reference/monoids/index.rst index f41d8f09841..d2847929f19 100644 --- a/src/doc/en/reference/monoids/index.rst +++ b/src/doc/en/reference/monoids/index.rst @@ -13,6 +13,7 @@ finite number of indeterminates. sage/monoids/free_monoid_element sage/monoids/free_abelian_monoid sage/monoids/free_abelian_monoid_element + sage/monoids/hecke_monoid sage/monoids/indexed_free_monoid sage/monoids/string_monoid_element sage/monoids/string_monoid diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 24afbcfdcbc..0c9ed98861e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -508,14 +508,11 @@ def orthogonal_idempotents_central_mod_rad(self): sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True - We construct orthogonal idempotents of the algebra of the + We construct orthogonal idempotents for the algebra of the `0`-Hecke monoid:: - sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup - sage: W = WeylGroup(['A', 3]); W.rename("W") - sage: ambient_monoid = FiniteSetMaps(W, action="right") - sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: A = AutomaticSemigroup(pi, one=ambient_monoid.one()).algebra(QQ) + sage: from sage.monoids.hecke_monoid import HeckeMonoid + sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) sage: idempotents = A.orthogonal_idempotents_central_mod_rad() sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True @@ -681,15 +678,10 @@ def cartan_invariants_matrix(self): [0 0 0 0 0 0 0 2 0] [0 0 0 0 0 0 0 0 2] - With the 0-Hecke monoid algebra:: + With the algebra of the `0`-Hecke monoid:: - sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup - sage: W = SymmetricGroup(4); W.rename("W") - sage: ambient_monoid = FiniteSetMaps(W, action="right") - sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: H4 = ambient_monoid.submonoid(pi); H4 - A submonoid of (Maps from W to itself) with 3 generators - sage: A = H4.algebra(QQ) + sage: from sage.monoids.hecke_monoid import HeckeMonoid + sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0] [0 1 1 1 0 0 0 0] @@ -903,10 +895,8 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): With the algebra of the `0`-Hecke monoid:: - sage: W = SymmetricGroup(4); W.rename("W") - sage: ambient_monoid = FiniteSetMaps(W, action="right") - sage: pi = W.simple_projections(length_increasing=True).map(ambient_monoid) - sage: A = ambient_monoid.submonoid(pi).algebra(QQ) + sage: from sage.monoids.hecke_monoid import HeckeMonoid + sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) sage: idempotents = A.orthogonal_idempotents_central_mod_rad() sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True From 7dcb52394e0465210352ecc4c614d9b8130a58a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Fri, 24 Apr 2015 13:18:35 +0200 Subject: [PATCH 506/665] add patch to libgd to fix build error --- .../libgd/patches/gd-2.1.1-libvpx-1.4.0.patch | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 build/pkgs/libgd/patches/gd-2.1.1-libvpx-1.4.0.patch diff --git a/build/pkgs/libgd/patches/gd-2.1.1-libvpx-1.4.0.patch b/build/pkgs/libgd/patches/gd-2.1.1-libvpx-1.4.0.patch new file mode 100644 index 00000000000..c698972539e --- /dev/null +++ b/build/pkgs/libgd/patches/gd-2.1.1-libvpx-1.4.0.patch @@ -0,0 +1,37 @@ +From d41eb72cd4545c394578332e5c102dee69e02ee8 Mon Sep 17 00:00:00 2001 +From: Remi Collet +Date: Tue, 7 Apr 2015 13:11:03 +0200 +Subject: [PATCH] Fix build with latest libvpx 1.4.0 + +These new constants exist at least since 1.0.0 +Compatibility ones have been droped in 1.4.0 +--- + src/webpimg.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/webpimg.c b/src/webpimg.c +index cf73d64..e49fcc6 100644 +--- a/src/webpimg.c ++++ b/src/webpimg.c +@@ -711,14 +711,14 @@ static WebPResult VPXEncode(const uint8* Y, + codec_ctl(&enc, VP8E_SET_STATIC_THRESHOLD, 0); + codec_ctl(&enc, VP8E_SET_TOKEN_PARTITIONS, 2); + +- vpx_img_wrap(&img, IMG_FMT_I420, ++ vpx_img_wrap(&img, VPX_IMG_FMT_I420, + y_width, y_height, 16, (uint8*)(Y)); +- img.planes[PLANE_Y] = (uint8*)(Y); +- img.planes[PLANE_U] = (uint8*)(U); +- img.planes[PLANE_V] = (uint8*)(V); +- img.stride[PLANE_Y] = y_stride; +- img.stride[PLANE_U] = uv_stride; +- img.stride[PLANE_V] = uv_stride; ++ img.planes[VPX_PLANE_Y] = (uint8*)(Y); ++ img.planes[VPX_PLANE_U] = (uint8*)(U); ++ img.planes[VPX_PLANE_V] = (uint8*)(V); ++ img.stride[VPX_PLANE_Y] = y_stride; ++ img.stride[VPX_PLANE_U] = uv_stride; ++ img.stride[VPX_PLANE_V] = uv_stride; + + res = vpx_codec_encode(&enc, &img, 0, 1, 0, VPX_DL_BEST_QUALITY); + From fd489bf083f69e84c48ead6b6b7afa521593d783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Apitzsch?= Date: Fri, 24 Apr 2015 13:19:10 +0200 Subject: [PATCH 507/665] update libgd to 2.1.1 --- build/pkgs/libgd/checksums.ini | 6 +++--- build/pkgs/libgd/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/libgd/checksums.ini b/build/pkgs/libgd/checksums.ini index 875066a6e64..a20da4e15bb 100644 --- a/build/pkgs/libgd/checksums.ini +++ b/build/pkgs/libgd/checksums.ini @@ -1,4 +1,4 @@ tarball=libgd-VERSION.tar.bz2 -sha1=74446b68bce0c1d02cd06966f05c840abc56dcb1 -md5=0a1d9231998df8056cafa5963ac0c228 -cksum=1829449569 +sha1=beab6fe12a8669ecc790316634b1c69b33a5d348 +md5=d3f1a992ac9c550ebc6da89c147f89af +cksum=1437614959 diff --git a/build/pkgs/libgd/package-version.txt b/build/pkgs/libgd/package-version.txt index 7e41e597591..ac87272599a 100644 --- a/build/pkgs/libgd/package-version.txt +++ b/build/pkgs/libgd/package-version.txt @@ -1 +1 @@ -2.1.0.p0 +2.1.1.p0 From 6e81e4b500f7698446fd19de792744a33667eafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:01:59 +0200 Subject: [PATCH 508/665] 16659: proofreading and little additions to the doc; small refactoring of the code --- .../finite_dimensional_algebras_with_basis.py | 154 +++++++++------- src/sage/categories/semisimple_algebras.py | 172 ++++++++++-------- 2 files changed, 184 insertions(+), 142 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 0c9ed98861e..f700b5269d8 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -437,7 +437,7 @@ def principal_ideal(self, a, side='left'): [x, a, b] """ return self.submodule([(a * b if side=='right' else b * a) - for b in self.basis()]) + for b in self.basis()]) @cached_method def orthogonal_idempotents_central_mod_rad(self): @@ -641,6 +641,7 @@ def cartan_invariants_matrix(self): .. SEEALSO:: - :meth:`peirce_decomposition` + - :meth:`isotypic_projective_modules` EXAMPLES: @@ -692,53 +693,70 @@ def cartan_invariants_matrix(self): [0 0 0 0 1 1 1 0] [0 0 0 0 0 0 0 1] """ + from sage.rings.integer_ring import ZZ A_quo = self.semisimple_quotient() - orth_quo = A_quo.central_orthogonal_idempotents() + idempotents_quo = A_quo.central_orthogonal_idempotents() # Dimension of simple modules - dimSimples = [sqrt(A_quo.principal_ideal(e).dimension()) for e in - orth_quo] + dim_simples = [sqrt(A_quo.principal_ideal(e).dimension()) + for e in idempotents_quo] # Orthogonal idempotents - orth = self.orthogonal_idempotents_central_mod_rad() - return Matrix(self.base_ring(), - len(orth), - lambda i,j: self.peirce_summand(orth[i], - orth[j]).dimension()/(dimSimples[i]*dimSimples[j])) + idempotents = self.orthogonal_idempotents_central_mod_rad() + def C(i,j): + summand = self.peirce_summand(idempotents[i], idempotents[j]) + return summand.dimension() / (dim_simples[i]*dim_simples[j]) + return Matrix(ZZ, len(idempotents), C) - def projective_isotypics(self, side='left'): + def isotypic_projective_modules(self, side='left'): r""" - Return the list of isotypic projective ``side`` ``self``-modules. + Return the isotypic projective ``side`` ``self``-modules. - Let `(e_i)` be the orthogonal idempotents lifted from the central - orthogonal idempotents of the semisimple algebra. The regular - representation `A` can be decomposed as a direct sum - `\bigoplus_i P_i` with `P_i = e_i A`. - The projective modules `P_i` are isotypic in the sense that all - their direct summands are isomorphic. + Let `P_i` be representatives of the indecomposable + projective ``side``-modules of this finite dimensional + algebra `A`, and `S_i` be the associated simple modules. - .. NOTE:: + The regular ``side`` representation of `A` can be + decomposed as a direct sum `A = \bigoplus_i Q_i` where + each `Q_i` is an isotypic projective module; namely `Q_i` + is the direct sum of `\dim S_i` copies of the + indecomposable projective module `P_i`. This decomposition + is not unique. - The number of summands of `P_i` is the dimension of the associated - simple module. + The isotypic projective modules are constructed as + `Q_i=e_iA`, where the `(e_i)_i` is the decomposition of + the identity into orthogonal idempotents obtained by + lifting the central orthogonal idempotents of the + semisimple quotient of `A`. - OUTPUT: + INPUT: - - return a list of modules `e_i A` for `(e_i)` a set of orthogonal - idempotents lifted from central orthogonal idempotents of the - semisimple quotient. + - ``side`` -- 'left' or 'right' (default: 'left') + + OUTPUT: a list of subspaces of ``self``. EXAMPLES:: - sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() - sage: projs = A.projective_isotypics(side="left"); projs + sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver + (containing the arrows a:x->y and b:x->y) over Rational Field + sage: Q = A.isotypic_projective_modules(side="left"); Q [Free module generated by {0, 1, 2} over Rational Field, Free module generated by {0} over Rational Field] + sage: [[x.lift() for x in Qi.basis()] + ....: for Qi in Q] + [[y, a, b], + [x]] - We check that the sum of the dimensions of the indecomposable - projective module is the dimension of ``self``: + We check that the sum of the dimensions of the isotypic + projective modules is the dimension of ``self``:: - sage: sum([P.dimension() for P in projs]) == A.dimension() + sage: sum([Qi.dimension() for Qi in Q]) == A.dimension() True + .. SEEALSO:: + + - :meth:`orthogonal_idempotents_central_mod_rad` + - :meth:`peirce_decomposition` """ return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents_central_mod_rad()] @@ -746,18 +764,15 @@ def projective_isotypics(self, side='left'): @cached_method def peirce_summand(self, ei, ej): r""" - Return the Peirce decomposition summand `e_i A e_j` as a - subspace of the algebra. + Return the Peirce decomposition summand `e_i A e_j`. INPUT: - ``self`` -- an algebra `A` - - `e_i` -- an idempotent of `A` - - `e_j` -- an idempotent of `A` - OUTPUT: + - ``ei``, ``ej`` -- two idempotents of `A` - - `e_i A e_j` as a subspace of `A` + OUTPUT: `e_i A e_j`, as a subspace of `A`. .. SEEALSO:: :meth:`peirce_decomposition` @@ -770,7 +785,9 @@ def peirce_summand(self, ei, ej): sage: A.peirce_summand(idemp[0], idemp[1]) Free module generated by {} over Rational Field - We recover the unique 2 dimensional representation of S4:: + We recover the `2\times2` block of `\QQ[S_4]` + corresponding to the unique simple module of dimension `2` + of the symmetric group `S_4`:: sage: A4 = SymmetricGroup(4).algebra(QQ) sage: e = A4.central_orthogonal_idempotents()[2] @@ -789,7 +806,7 @@ def peirce_decomposition(self, idempotents=None, check=True): r""" Return a Peirce decomposition of ``self``. - Let `(e_i)` be a collection of orthogonal idempotents of + Let `(e_i)_i` be a collection of orthogonal idempotents of `A` with sum `1`. The *Peirce decomposition* of `A` is the decomposition of `A` into the direct sum of the subspaces `e_i A e_j`. @@ -805,9 +822,9 @@ def peirce_decomposition(self, idempotents=None, check=True): INPUT: - - ``idempotents`` -- a finite collection of orthogonal - idempotents of the algebra that sum to `1` (default: the - idempotents returned by + - ``idempotents`` -- a list of orthogonal idempotents + `(e_i)_{i=0,\ldots,n}` of the algebra that sum to `1` + (default: the idempotents returned by :meth:`orthogonal_idempotents_central_mod_rad`) - ``check`` -- (default:True) whether to check that the idempotents @@ -815,8 +832,8 @@ def peirce_decomposition(self, idempotents=None, check=True): OUTPUT: - The subspaces `e_i A e_j`, where `e_i` and `e_j` run - through ``list_idempotents``. + A list of lists `l` such that ``l[i][j]`` is the subspace + `e_i A e_j`. .. SEEALSO:: @@ -832,30 +849,44 @@ def peirce_decomposition(self, idempotents=None, check=True): sage: A.orthogonal_idempotents_central_mod_rad() [y, x] sage: decomposition = A.peirce_decomposition(); decomposition - [Free module generated by {0} over Rational Field, - Free module generated by {} over Rational Field, - Free module generated by {0, 1} over Rational Field, - Free module generated by {0} over Rational Field] - sage: [[x.lift() for x in summand.basis()] - ....: for summand in decomposition] - [[y], - [], - [a, b], - [x]] - - .. TODO:: - - - Specify the order in which the summands are returned, - or return a list of list or a dictionary. + [[Free module generated by {0} over Rational Field, + Free module generated by {} over Rational Field], + [Free module generated by {0, 1} over Rational Field, + Free module generated by {0} over Rational Field]] + sage: [ [[x.lift() for x in decomposition[i][j].basis()] + ....: for j in range(2)] + ....: for i in range(2)] + [[[y], []], + [[a, b], [x]]] + + We recover that the group algebra of the symmetric group + `S_4` is a block matrix algebra:: + + sage: A = SymmetricGroup(4).algebra(QQ) + sage: decomposition = A.peirce_decomposition() # long time + sage: [[decomposition[i][j].dimension() # long time (4s) + ....: for j in range(len(decomposition))] + ....: for i in range(len(decomposition))] + [[4, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 9, 0], + [0, 0, 0, 0, 9]] + + The dimension of each block is `d^2`, where `d` is the + dimension of the corresponding simple module of `S_4`. The + latter are given by:: + + sage: [p.standard_tableaux().cardinality() for p in Partitions(4)] + [1, 3, 2, 3, 1] """ if idempotents is None: idempotents = self.orthogonal_idempotents_central_mod_rad() if check: if not self.is_identity_decomposition_into_orthogonal_idempotents(idempotents): raise ValueError("Not a decomposition of the identity into orthogonal idempotents") - return [self.peirce_summand(ei, ej) - for ei in idempotents - for ej in idempotents] + return [[self.peirce_summand(ei, ej) for ej in idempotents] + for ei in idempotents] def is_identity_decomposition_into_orthogonal_idempotents(self, l): r""" @@ -904,8 +935,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): .. TODO:: Add examples of elements that are orthogonal and sum - to the identity yet are not idempotent and reciprocally. - + to the identity yet are not idempotent, and reciprocally. """ return (self.sum(l) == self.one() and all(e*e == e for e in l) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 2abbce6dacb..23343fa5aef 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -116,39 +116,37 @@ class ParentMethods: @cached_method def central_orthogonal_idempotents(self): r""" - Return a maximal list of central orthogonal idempotents of - ``self``. + Return a maximal list of central orthogonal + idempotents of ``self``. - Central orthogonal idempotents of an algebra `A` are - idempotents `(e_1, \dots, e_n)` such that `e_i e_j = 0` if - `i \neq j`. Moreover, all `e_i` commute with all elements - of `A` (central). + *Central orthogonal idempotents* of an algebra `A` + are idempotents `(e_1, \dots, e_n)` in the center + of `A` such that `e_i e_j = 0` whenever `i \neq j`. + + With the maximality condition, they sum up to `1` + and are uniquely determined (up to order). INPUT: - ``self`` -- a semisimple algebra. - OUTPUT: - - - a complete list of central orthogonal idempotents. + EXAMPLES: - EXAMPLES:: + For the algebra of the symmetric group `S_3`, we + recover the sum and alternating sum of all + permutations, together with a third idempotent:: - sage: import itertools sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: orths = A3.central_orthogonal_idempotents(); orths - [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), 1/6*() + 1/6*(2,3) - + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), - 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + - 1/6*(1,3,2) - 1/6*(1,3)] - sage: all(e*e == e for e in orths) - True - sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orths, orths) if e != f) - True - sage: all(e*a == a*e for e in orths for a in A3.basis()) + sage: idempotents = A3.central_orthogonal_idempotents() + sage: idempotents + [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), + 1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] + sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True - :: + For the semisimple quotient of a quiver algebra, + we recover the vertices of the quiver:: sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A An example of a finite dimensional algebra with basis: @@ -169,16 +167,13 @@ class ParentMethods: @cached_method def _orthogonal_decomposition(self, generators=None): r""" - Return a list of orthogonal quasi-idempotents of a - semisimple commutative finite dimensional algebra - ``self``. + Return a list of orthogonal quasi-idempotents of this + semisimple commutative finite dimensional algebra. INPUT: - - ``self`` a finite dimensional semisimple commutative - algebra. - - ``generators`` a list of generators of ``self``. By - default it will be the basis of ``self``. + - ``generators`` -- a list of generators of + ``self`` (default: the basis of ``self``) OUTPUT: @@ -190,16 +185,18 @@ def _orthogonal_decomposition(self, generators=None): ALGORITHM: - A commutative semisimple algebra `A` is a direct - sum of dimension 1 sub-algebras thanks to Schur - Lemma. The algorithm is recursive a proceed in two - steps: + Thanks to Schur's Lemma, a commutative + semisimple algebra `A` is a direct sum of + dimension 1 subalgebras. The algorithm is + recursive and proceeds as follows: 0. If `A` is of dimension 1, return a non zero element. - 1. Find a generator `a \in A` such that the - morphism `x \mapsto ax` has at least two (right) - eigenspaces. + + 1. Otherwise: find one of the generators such + that the morphism `x \mapsto ax` has at + least two (right) eigenspaces. + 2. Decompose both eigenspaces recursively. EXAMPLES:: @@ -218,21 +215,25 @@ def _orthogonal_decomposition(self, generators=None): .. TODO:: - Improve speed by only using matrix operations, if - possible. + Improve speed by using matrix operations + only, if possible. """ - # Main program + category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() if generators is None: generators = self.basis().list() if self.dimension() == 1: return self.basis().list() - def rec(space, generators): + def rec(space, generators=None): + if generators is None: + generators = space.basis().list() + generators = list(generators) + if space.dimension() == 1: return space.basis().list() eigenspaces = [] - # Searching a good generator... + # Searching for a good generator ... while len(eigenspaces) < 2: if generators == []: raise Exception("Unable to fully decompose...") @@ -241,60 +242,71 @@ def rec(space, generators): gen*space.basis()[i], codomain=space, triangular='lower') - eigenspaces = phi.matrix(space.base_ring()).eigenspaces_right() + eigenspaces = phi.matrix().eigenspaces_right() - # Gotcha! Let's settle the algebra... - eigenspaces = [vector_space for _, vector_space in eigenspaces] - eigenspaces = [[space.from_vector(vector) - for vector in eigenspace.basis()] - for eigenspace in eigenspaces] - decomp = [space.submodule(v, - category=SemisimpleAlgebras(space.base_ring()).WithBasis().FiniteDimensional().Commutative().Subobjects()) - for v in eigenspaces] + # Gotcha! Let's split the algebra ... + subalgebras = \ + [space.submodule(map(space.from_vector, eigenspace.basis()), + category=category) + for eigenvalue, eigenspace in eigenspaces] # Decompose recursively each eigenspace - return map(lambda x: x.lift(), [x for eigenspace in - decomp for x in rec(eigenspace, eigenspace.basis().list())]) + return [idempotent.lift() + for subalgebra in subalgebras + for idempotent in rec(subalgebra)] return rec(self, generators) @cached_method def central_orthogonal_idempotents(self): r""" - Return the set of central orthogonal idempotents of ``self``. + Return the central orthogonal idempotents of + this semisimple commutative algebra. - INPUT: - - - ``self`` a commutative semisimple algebra. + Those idempotents form a maximal decomposition + of the identity into primitive orthogonal + idempotents. OUTPUT: - - list of central orthogonal idempotents of ``self``. - - .. NOTE:: - - All idempotents returned are primitive. + - a list of orthogonal idempotents of ``self``. EXAMPLES:: - sage: import itertools - sage: A5 = SymmetricGroup(5).algebra(QQ) - sage: Z5 = A5.center() - sage: orths = Z5.central_orthogonal_idempotents(); orths - [3/10*B[0] - 1/10*B[2] + 1/20*B[6], 1/120*B[0] + - 1/120*B[1] + 1/120*B[2] + 1/120*B[3] + 1/120*B[4] + - 1/120*B[5] + 1/120*B[6], 1/120*B[0] - 1/120*B[1] + - 1/120*B[2] + 1/120*B[3] - 1/120*B[4] - 1/120*B[5] + - 1/120*B[6], 5/24*B[0] + 1/24*B[1] + 1/24*B[2] - - 1/24*B[3] + 1/24*B[4] - 1/24*B[5], 5/24*B[0] - - 1/24*B[1] + 1/24*B[2] - 1/24*B[3] - 1/24*B[4] + - 1/24*B[5], 2/15*B[0] + 1/15*B[1] + 1/30*B[3] - - 1/30*B[4] - 1/30*B[6], 2/15*B[0] - 1/15*B[1] + - 1/30*B[3] + 1/30*B[4] - 1/30*B[6]] - sage: all(e*e == e for e in orths) - True - sage: all(e*f == f*e and e*f == 0 for e,f in itertools.product(orths, orths) if e != f) + sage: A4 = SymmetricGroup(4).algebra(QQ) + sage: Z4 = A4.center() + sage: idempotents = Z4.central_orthogonal_idempotents() + sage: idempotents + [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], + 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], + 1/6*B[0] + 1/6*B[2] - 1/12*B[3], + 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], + 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] + + Lifting those idempotents from the center, we + recognize among them the sum and alternating + sum of all permutations:: + + sage: [e.lift() for e in idempotents] + [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + + 1/24*(1,3,4,2) + 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + + 1/24*(1,3,2,4) + 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + + 1/24*(1,4) + 1/24*(1,4,2,3) + 1/24*(1,4)(2,3), + ..., + 1/24*() - 1/24*(3,4) - 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + - 1/24*(2,4) - 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + - 1/24*(1,2,3,4) - 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + - 1/24*(1,3,4,2) - 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + - 1/24*(1,3,2,4) - 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + - 1/24*(1,4) - 1/24*(1,4,2,3) + 1/24*(1,4)(2,3)] + + We check that they indeed form a decomposition + of the identity of `Z_4` into orthogonal idempotents:: + + sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e for - e in self._orthogonal_decomposition()] + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in self._orthogonal_decomposition()] From 19756de9e9367efc85add11872bbf03d873b948f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:02:54 +0200 Subject: [PATCH 509/665] 16659: minor line-split in the doc --- src/sage/categories/magmas.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index ea471ae34b5..3b8d809bc35 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -1045,7 +1045,8 @@ def product(self, x, y): sage: S = Semigroups().Subquotients().example() sage: S - An example of a (sub)quotient semigroup: a quotient of the left zero semigroup + An example of a (sub)quotient semigroup: + a quotient of the left zero semigroup sage: S.product(S(19), S(3)) 19 From fd8e1ad375037e078905ae220bc9e543d65a67be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:23:37 +0200 Subject: [PATCH 510/665] 16659: refactored _orthogonal_decomposition and updated doctests accordingly --- .../finite_dimensional_algebras_with_basis.py | 70 +++++++------- src/sage/categories/semisimple_algebras.py | 95 +++++++++---------- 2 files changed, 79 insertions(+), 86 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index f700b5269d8..91a30e28843 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -478,7 +478,7 @@ def orthogonal_idempotents_central_mod_rad(self): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.orthogonal_idempotents_central_mod_rad() - [y, x] + [x, y] :: @@ -486,15 +486,15 @@ def orthogonal_idempotents_central_mod_rad(self): An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) sage: idempotents = A.orthogonal_idempotents_central_mod_rad() - sage: idempotents - [-1/2*B[8] + 1/2*B[4], - 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], + sage: sorted(idempotents, key=str) + [-1/2*B[3] + 1/2*B[9], + -1/2*B[8] + 1/2*B[4], + -B[0] + 1/2*B[3] + 1/2*B[9], + -B[0] + 1/2*B[4] + 1/2*B[8], 1/4*B[1] + 1/2*B[3] + 1/4*B[5] - 1/4*B[7] - 1/2*B[9] - 1/4*B[11], - -1/2*B[3] + 1/2*B[9], - B[0], - 1/2*B[8] + 1/2*B[4] - B[0], 1/4*B[1] + 1/4*B[11] - 1/4*B[5] - 1/4*B[7], - -B[0] + 1/2*B[3] + 1/2*B[9], + 1/4*B[1] - 1/2*B[4] - 1/4*B[5] + 1/4*B[7] + 1/2*B[8] - 1/4*B[11], + B[0], B[0] + 1/4*B[1] - 1/2*B[3] - 1/2*B[4] + 1/4*B[5] + 1/4*B[7] - 1/2*B[8] - 1/2*B[9] + 1/4*B[11]] sage: sum(idempotents) == 1 True @@ -660,8 +660,8 @@ def cartan_invariants_matrix(self): sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: A.cartan_invariants_matrix() - [1 0] - [2 1] + [1 2] + [0 1] In the commutative case, the Cartan invariant matrix is diagonal:: @@ -670,14 +670,14 @@ def cartan_invariants_matrix(self): sage: A = Z12.algebra(QQ) sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0 0] - [0 2 0 0 0 0 0 0 0] - [0 0 1 0 0 0 0 0 0] + [0 1 0 0 0 0 0 0 0] + [0 0 2 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0] - [0 0 0 0 1 0 0 0 0] + [0 0 0 0 2 0 0 0 0] [0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 2 0] - [0 0 0 0 0 0 0 0 2] + [0 0 0 0 0 0 0 0 1] With the algebra of the `0`-Hecke monoid:: @@ -685,12 +685,12 @@ def cartan_invariants_matrix(self): sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) sage: A.cartan_invariants_matrix() [1 0 0 0 0 0 0 0] - [0 1 1 1 0 0 0 0] - [0 1 1 1 0 0 0 0] - [0 1 1 2 0 1 0 0] - [0 0 0 0 1 1 1 0] - [0 0 0 1 1 2 1 0] - [0 0 0 0 1 1 1 0] + [0 2 1 0 1 1 0 0] + [0 1 1 0 1 0 0 0] + [0 0 0 1 0 1 1 0] + [0 1 1 0 1 0 0 0] + [0 1 0 1 0 2 1 0] + [0 0 0 1 0 1 1 0] [0 0 0 0 0 0 0 1] """ from sage.rings.integer_ring import ZZ @@ -740,12 +740,12 @@ def isotypic_projective_modules(self, side='left'): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: Q = A.isotypic_projective_modules(side="left"); Q - [Free module generated by {0, 1, 2} over Rational Field, - Free module generated by {0} over Rational Field] + [Free module generated by {0} over Rational Field, + Free module generated by {0, 1, 2} over Rational Field] sage: [[x.lift() for x in Qi.basis()] ....: for Qi in Q] - [[y, a, b], - [x]] + [[x], + [y, a, b]] We check that the sum of the dimensions of the isotypic projective modules is the dimension of ``self``:: @@ -780,9 +780,9 @@ def peirce_summand(self, ei, ej): sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() sage: idemp = A.orthogonal_idempotents_central_mod_rad() - sage: A.peirce_summand(idemp[1], idemp[0]) - Free module generated by {0, 1} over Rational Field sage: A.peirce_summand(idemp[0], idemp[1]) + Free module generated by {0, 1} over Rational Field + sage: A.peirce_summand(idemp[1], idemp[0]) Free module generated by {} over Rational Field We recover the `2\times2` block of `\QQ[S_4]` @@ -847,17 +847,17 @@ def peirce_decomposition(self, idempotents=None, check=True): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field sage: A.orthogonal_idempotents_central_mod_rad() - [y, x] + [x, y] sage: decomposition = A.peirce_decomposition(); decomposition [[Free module generated by {0} over Rational Field, - Free module generated by {} over Rational Field], - [Free module generated by {0, 1} over Rational Field, + Free module generated by {0, 1} over Rational Field], + [Free module generated by {} over Rational Field, Free module generated by {0} over Rational Field]] sage: [ [[x.lift() for x in decomposition[i][j].basis()] ....: for j in range(2)] ....: for i in range(2)] - [[[y], []], - [[a, b], [x]]] + [[[x], [a, b]], + [[], [y]]] We recover that the group algebra of the symmetric group `S_4` is a block matrix algebra:: @@ -867,11 +867,11 @@ def peirce_decomposition(self, idempotents=None, check=True): sage: [[decomposition[i][j].dimension() # long time (4s) ....: for j in range(len(decomposition))] ....: for i in range(len(decomposition))] - [[4, 0, 0, 0, 0], - [0, 1, 0, 0, 0], - [0, 0, 1, 0, 0], + [[1, 0, 0, 0, 0], + [0, 9, 0, 0, 0], + [0, 0, 4, 0, 0], [0, 0, 0, 9, 0], - [0, 0, 0, 0, 9]] + [0, 0, 0, 0, 1]] The dimension of each block is `d^2`, where `d` is the dimension of the corresponding simple module of `S_4`. The diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 23343fa5aef..e530c207566 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -139,8 +139,8 @@ def central_orthogonal_idempotents(self): sage: A3 = SymmetricGroup(3).algebra(QQ) sage: idempotents = A3.central_orthogonal_idempotents() sage: idempotents - [2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), - 1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + [1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + 2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True @@ -154,7 +154,7 @@ def central_orthogonal_idempotents(self): the arrows a:x->y and b:x->y) over Rational Field sage: Aquo = A.semisimple_quotient() sage: Aquo.central_orthogonal_idempotents() - [B['y'], B['x']] + [B['x'], B['y']] """ return [x.lift() for x in self.center().central_orthogonal_idempotents()] @@ -199,63 +199,56 @@ def _orthogonal_decomposition(self, generators=None): 2. Decompose both eigenspaces recursively. - EXAMPLES:: + EXAMPLES: + + We compute an orthogonal decomposition of the + center of the algebra of the symmetric group + `S_4`:: - sage: G5 = SymmetricGroup(5) - sage: A5 = G5.algebra(QQ) - sage: Z5 = A5.center() - sage: Z5._orthogonal_decomposition() - [B[0] - 1/3*B[2] + 1/6*B[6], B[0] + B[1] + B[2] + - B[3] + B[4] + B[5] + B[6], B[0] - B[1] + B[2] + B[3] - - B[4] - B[5] + B[6], B[0] + 1/5*B[1] + 1/5*B[2] - - 1/5*B[3] + 1/5*B[4] - 1/5*B[5], B[0] - 1/5*B[1] + - 1/5*B[2] - 1/5*B[3] - 1/5*B[4] + 1/5*B[5], B[0] + - 1/2*B[1] + 1/4*B[3] - 1/4*B[4] - 1/4*B[6], B[0] - - 1/2*B[1] + 1/4*B[3] + 1/4*B[4] - 1/4*B[6]] + sage: Z4 = SymmetricGroup(4).algebra(QQ).center() + sage: Z4._orthogonal_decomposition() + [B[0] + B[1] + B[2] + B[3] + B[4], + B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], + B[0] + B[2] - 1/2*B[3], + B[0] - 1/3*B[1] - 1/3*B[2] + 1/3*B[4], + B[0] - B[1] + B[2] + B[3] - B[4]] .. TODO:: Improve speed by using matrix operations only, if possible. """ + if self.dimension() == 1: + return self.basis().list() + category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() + if generators is None: generators = self.basis().list() - if self.dimension() == 1: - return self.basis().list() - def rec(space, generators=None): - if generators is None: - generators = space.basis().list() - generators = list(generators) - - if space.dimension() == 1: - return space.basis().list() - eigenspaces = [] - - # Searching for a good generator ... - while len(eigenspaces) < 2: - if generators == []: - raise Exception("Unable to fully decompose...") - gen = generators.pop() - phi = space.module_morphism(on_basis=lambda i: - gen*space.basis()[i], - codomain=space, - triangular='lower') - eigenspaces = phi.matrix().eigenspaces_right() - - # Gotcha! Let's split the algebra ... - subalgebras = \ - [space.submodule(map(space.from_vector, eigenspace.basis()), - category=category) - for eigenvalue, eigenspace in eigenspaces] - - # Decompose recursively each eigenspace - return [idempotent.lift() - for subalgebra in subalgebras - for idempotent in rec(subalgebra)] - - return rec(self, generators) + # Searching for a good generator ... + for gen in generators: + # Computing the eigenspaces of the + # linear map x -> gen*x + phi = self.module_morphism( + on_basis=lambda i: + gen*self.term(i), + codomain=self) + eigenspaces = phi.matrix().eigenspaces_right() + + if len(eigenspaces) >= 2: + # Gotcha! Let's split the algebra according to the eigenspaces + subalgebras = [ + self.submodule(map(self.from_vector, eigenspace.basis()), + category=category) + for eigenvalue, eigenspace in eigenspaces] + + # Decompose recursively each eigenspace + return [idempotent.lift() + for subalgebra in subalgebras + for idempotent in subalgebra._orthogonal_decomposition()] + # TODO: Should this be an assertion check? + raise Exception("Unable to fully decompose %s!"%self) @cached_method def central_orthogonal_idempotents(self): @@ -278,9 +271,9 @@ def central_orthogonal_idempotents(self): sage: idempotents = Z4.central_orthogonal_idempotents() sage: idempotents [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], - 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], - 1/6*B[0] + 1/6*B[2] - 1/12*B[3], 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], + 1/6*B[0] + 1/6*B[2] - 1/12*B[3], + 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] Lifting those idempotents from the center, we From cc327efe6f3a221ae089d68558e5296cc9fc295c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:31:39 +0200 Subject: [PATCH 511/665] 16659: improved documentation for _orthogonal_decomposition --- src/sage/categories/semisimple_algebras.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index e530c207566..5bdf29285ed 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -167,8 +167,8 @@ class ParentMethods: @cached_method def _orthogonal_decomposition(self, generators=None): r""" - Return a list of orthogonal quasi-idempotents of this - semisimple commutative finite dimensional algebra. + Return a maximal list of orthogonal quasi-idempotents of + this finite dimensional semisimple commutative algebra. INPUT: @@ -177,11 +177,18 @@ def _orthogonal_decomposition(self, generators=None): OUTPUT: - - list of elements of ``self`` each generating a one - dimensional simple submodule summand of ``self``. The - list is maximal in the sense that no quasi-idempotent - `e` can be decomposed as a sum `e = e_1 + e_2` of - quasi-idempotents elements. + - a list of quasi-idempotent elements of ``self``. + + Each quasi-idempotent `e` spans a one + dimensional (non unital) subalgebra of + ``self``, and cannot be decomposed as a sum + `e=e_1+e_2` of quasi-idempotents elements. + All together, they form a basis of ``self``. + + Up to the order and scalar factors, the result + is unique. In particular it does not depend on + the provided generators which are only used + for improved efficiency. ALGORITHM: From e00dfdb8c49ba0105922aeeabab5bcb234bceaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:33:21 +0200 Subject: [PATCH 512/665] 16659: improved documentation for _orthogonal_decomposition --- src/sage/categories/semisimple_algebras.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 5bdf29285ed..bed9a2d17e3 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -223,7 +223,8 @@ def _orthogonal_decomposition(self, generators=None): .. TODO:: Improve speed by using matrix operations - only, if possible. + only, or even better delegating to a + multivariate polynomial solver. """ if self.dimension() == 1: return self.basis().list() From cce7d3db05f6f10fec8c19a055987c61eee4b771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Fri, 24 Apr 2015 16:58:05 +0200 Subject: [PATCH 513/665] 17696: added crosslinks --- .../categories/finite_dimensional_algebras_with_basis.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 91a30e28843..3fae7dfdbb3 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -435,6 +435,10 @@ def principal_ideal(self, a, side='left'): Free module generated by {0, 1, 2} over Rational Field sage: [B.lift() for B in xA.basis()] [x, a, b] + + .. SEEALSO:: + + - :meth:`peirce_summand` """ return self.submodule([(a * b if side=='right' else b * a) for b in self.basis()]) @@ -774,7 +778,10 @@ def peirce_summand(self, ei, ej): OUTPUT: `e_i A e_j`, as a subspace of `A`. - .. SEEALSO:: :meth:`peirce_decomposition` + .. SEEALSO:: + + - :meth:`peirce_decomposition` + - :meth:`principal_ideal` EXAMPLES:: From 467c7562922583e5918cf136925eb36b8c03edc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 24 Apr 2015 17:42:19 +0200 Subject: [PATCH 514/665] trac #17575 minor pep8 and doc details, reviewer commit --- .../combinat/posets/incidence_algebras.py | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index e476f98deaa..51525c96168 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -15,7 +15,6 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** - from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.categories.algebras import Algebras @@ -25,6 +24,7 @@ from copy import copy + class IncidenceAlgebra(CombinatorialFreeModule): r""" The incidence algebra of a poset. @@ -32,7 +32,7 @@ class IncidenceAlgebra(CombinatorialFreeModule): Let `P` be a poset and `R` be a commutative unital associative ring. The *incidence algebra* `I_P` is the algebra of functions `\alpha \colon P \times P \to R` such that `\alpha(x, y) = 0` - if `x \not\leq y` where multiplication is given by covolution: + if `x \not\leq y` where multiplication is given by convolution: .. MATH:: @@ -63,7 +63,7 @@ def __init__(self, R, P, prefix='I'): sage: P = posets.BooleanLattice(4) sage: I = P.incidence_algebra(QQ) - sage: TestSuite(I).run() + sage: TestSuite(I).run() # long time """ cat = Algebras(R).WithBasis() if P in FiniteEnumeratedSets(): @@ -96,7 +96,8 @@ def _repr_(self): Incidence algebra of Finite lattice containing 16 elements over Rational Field """ - return "Incidence algebra of {} over {}".format(self._poset, self.base_ring()) + return "Incidence algebra of {} over {}".format(self._poset, + self.base_ring()) def _coerce_map_from_(self, R): """ @@ -315,7 +316,7 @@ def __call__(self, x, y): P = self.parent()._poset x = P(x) y = P(y) - return self[x,y] + return self[x, y] @cached_method def to_matrix(self): @@ -357,7 +358,7 @@ def to_matrix(self): MS = MatrixSpace(P.base_ring(), P._poset.cardinality(), sparse=True) L = P._linear_extension M = copy(MS.zero()) - for i,c in self: + for i, c in self: M[L.index(i[0]), L.index(i[1])] = c M.set_immutable() return M @@ -390,7 +391,7 @@ def is_unit(self): sage: y.is_unit() False """ - return all(self[x,x].is_unit() for x in self.parent()._poset) + return all(self[x, x].is_unit() for x in self.parent()._poset) def __invert__(self): """ @@ -425,8 +426,9 @@ def __invert__(self): raise ValueError("element is not invertible") inv = ~M L = self.parent()._linear_extension - return self.parent().sum_of_terms( ((L[i], L[j]), inv[i,j]) - for i,j in inv.nonzero_positions(copy=False) ) + return self.parent().sum_of_terms(((L[i], L[j]), inv[i, j]) + for i, j in inv.nonzero_positions(copy=False)) + class ReducedIncidenceAlgebra(CombinatorialFreeModule): r""" @@ -443,9 +445,9 @@ def __init__(self, I, prefix='R'): TESTS:: - sage: P = posets.BooleanLattice(4) + sage: P = posets.BooleanLattice(3) sage: R = P.incidence_algebra(QQ).reduced_subalgebra() - sage: TestSuite(R).run() + sage: TestSuite(R).run() # long time """ self._ambient = I EC = {} @@ -480,8 +482,8 @@ def _repr_(self): Reduced incidence algebra of Finite lattice containing 16 elements over Rational Field """ - return "Reduced incidence algebra of {} over {}".format( - self._ambient._poset, self.base_ring()) + msg = "Reduced incidence algebra of {} over {}" + return msg.format(self._ambient._poset, self.base_ring()) def poset(self): """ @@ -780,4 +782,3 @@ def lift(self): + 2*I[1, 3] + 2*I[2, 2] + 2*I[2, 3] + 2*I[3, 3] """ return self.parent().lift(self) - From ad3170e29e719419a850a628df130aef5bf17699 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 24 Apr 2015 18:05:55 +0200 Subject: [PATCH 515/665] Add patch from upstream for Cython memleak --- .../cython/patches/c_tuple_type_memleak.patch | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 build/pkgs/cython/patches/c_tuple_type_memleak.patch diff --git a/build/pkgs/cython/patches/c_tuple_type_memleak.patch b/build/pkgs/cython/patches/c_tuple_type_memleak.patch new file mode 100644 index 00000000000..7dc85aa31c0 --- /dev/null +++ b/build/pkgs/cython/patches/c_tuple_type_memleak.patch @@ -0,0 +1,124 @@ +commit bb4d9c2de71b7c7e1e02d9dfeae53f4547fa9d7d +Author: Stefan Behnel +Date: Fri Apr 24 17:57:23 2015 +0200 + + replace the incorrect and leaky global c-tuple type cache by a per-module one + +diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py +index 0fed86a..cce5c50 100644 +--- a/Cython/Compiler/ExprNodes.py ++++ b/Cython/Compiler/ExprNodes.py +@@ -6539,9 +6539,7 @@ class TupleNode(SequenceNode): + if any(type.is_pyobject or type.is_unspecified or type.is_fused for type in arg_types): + return tuple_type + else: +- type = PyrexTypes.c_tuple_type(arg_types) +- env.declare_tuple_type(self.pos, type) +- return type ++ return env.declare_tuple_type(self.pos, arg_types).type + + def analyse_types(self, env, skip_children=False): + if len(self.args) == 0: +@@ -6552,8 +6550,7 @@ class TupleNode(SequenceNode): + if not skip_children: + self.args = [arg.analyse_types(env) for arg in self.args] + if not self.mult_factor and not any(arg.type.is_pyobject or arg.type.is_fused for arg in self.args): +- self.type = PyrexTypes.c_tuple_type(arg.type for arg in self.args) +- env.declare_tuple_type(self.pos, self.type) ++ self.type = env.declare_tuple_type(self.pos, (arg.type for arg in self.args)).type + self.is_temp = 1 + return self + else: +diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py +index d6700d0..3ee9e9a 100644 +--- a/Cython/Compiler/Nodes.py ++++ b/Cython/Compiler/Nodes.py +@@ -1180,10 +1180,9 @@ class CTupleBaseTypeNode(CBaseTypeNode): + error(c.pos, "Tuple types can't (yet) contain Python objects.") + return error_type + component_types.append(type) +- type = PyrexTypes.c_tuple_type(component_types) +- entry = env.declare_tuple_type(self.pos, type) ++ entry = env.declare_tuple_type(self.pos, component_types) + entry.used = True +- return type ++ return entry.type + + + class FusedTypeNode(CBaseTypeNode): +diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py +index a4fc38d..bc61b6f 100644 +--- a/Cython/Compiler/PyrexTypes.py ++++ b/Cython/Compiler/PyrexTypes.py +@@ -3684,13 +3684,11 @@ class CTupleType(CType): + env.use_utility_code(self._convert_from_py_code) + return True + +-c_tuple_types = {} ++ + def c_tuple_type(components): + components = tuple(components) +- tuple_type = c_tuple_types.get(components) +- if tuple_type is None: +- cname = Naming.ctuple_type_prefix + type_list_identifier(components) +- tuple_type = c_tuple_types[components] = CTupleType(cname, components) ++ cname = Naming.ctuple_type_prefix + type_list_identifier(components) ++ tuple_type = CTupleType(cname, components) + return tuple_type + + +diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py +index 7409420..c2f3ac8 100644 +--- a/Cython/Compiler/Symtab.py ++++ b/Cython/Compiler/Symtab.py +@@ -610,8 +610,8 @@ class Scope(object): + self.sue_entries.append(entry) + return entry + +- def declare_tuple_type(self, pos, type): +- return self.outer_scope.declare_tuple_type(pos, type) ++ def declare_tuple_type(self, pos, components): ++ return self.outer_scope.declare_tuple_type(pos, components) + + def declare_var(self, name, type, pos, + cname = None, visibility = 'private', +@@ -1056,6 +1056,7 @@ class ModuleScope(Scope): + self.cached_builtins = [] + self.undeclared_cached_builtins = [] + self.namespace_cname = self.module_cname ++ self._cached_tuple_types = {} + for var_name in ['__builtins__', '__name__', '__file__', '__doc__', '__path__']: + self.declare_var(EncodedString(var_name), py_object_type, None) + +@@ -1075,18 +1076,24 @@ class ModuleScope(Scope): + + return self.outer_scope.lookup(name, language_level=language_level) + +- def declare_tuple_type(self, pos, type): +- cname = type.cname ++ def declare_tuple_type(self, pos, components): ++ components = tuple(components) ++ try: ++ ttype = self._cached_tuple_types[components] ++ except KeyError: ++ ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components) ++ cname = ttype.cname + entry = self.lookup_here(cname) + if not entry: + scope = StructOrUnionScope(cname) +- for ix, component in enumerate(type.components): ++ for ix, component in enumerate(components): + scope.declare_var(name="f%s" % ix, type=component, pos=pos) +- struct_entry = self.declare_struct_or_union(cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname) ++ struct_entry = self.declare_struct_or_union( ++ cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname) + self.type_entries.remove(struct_entry) +- type.struct_entry = struct_entry +- entry = self.declare_type(cname, type, pos, cname) +- type.entry = entry ++ ttype.struct_entry = struct_entry ++ entry = self.declare_type(cname, ttype, pos, cname) ++ ttype.entry = entry + return entry + + def declare_builtin(self, name, pos): From b5c18e65d21ff366cf7603ea1f12c6a4d404247f Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 24 Apr 2015 10:23:29 -0700 Subject: [PATCH 516/665] in documentation use V not v for IntegrableRepresentation --- .../root_system/integrable_representations.py | 168 +++++++++--------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index b5623276a03..aba50c89918 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -114,19 +114,19 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): multiplicity you use the method :meth:`m` and supply it with this tuple:: sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]); v + sage: V = IntegrableRepresentation(2*Lambda[0]); V Integrable representation of ['C', 2, 1] with highest weight 2*Lambda[0] - sage: v.m((3,5,3)) + sage: V.m((3,5,3)) 18 The :class:`IntegrableRepresentation` class has methods :meth:`to_weight` and :meth:`from_weight` to convert between this internal representation and the weight lattice:: - sage: delta = v.weight_lattice().null_root() - sage: v.to_weight((4,3,2)) + sage: delta = V.weight_lattice().null_root() + sage: V.to_weight((4,3,2)) -3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta - sage: v.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) + sage: V.from_weight(-3*Lambda[0] + 6*Lambda[1] - Lambda[2] - 4*delta) (4, 3, 2) To get more values, use the depth parameter:: @@ -141,8 +141,8 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): An example in type `C_2^{(1)}`:: sage: Lambda = RootSystem(['C',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: v.print_strings() # long time + sage: V = IntegrableRepresentation(2*Lambda[0]) + sage: V.print_strings() # long time 2*Lambda[0]: 1 2 9 26 77 194 477 1084 2387 5010 10227 20198 Lambda[0] + Lambda[2] - delta: 1 5 18 55 149 372 872 1941 4141 8523 17005 33019 2*Lambda[1] - delta: 1 4 15 44 122 304 721 1612 3469 7176 14414 28124 @@ -155,8 +155,8 @@ def __init__(self, Lam): EXAMPLES:: sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]) - sage: TestSuite(v).run() + sage: V = IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3]) + sage: TestSuite(V).run() """ CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ)) @@ -209,8 +209,8 @@ def weight_lattice(self): EXAMPLES:: - sage: v=IntegrableRepresentation(RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weight(0)) - sage: v.weight_lattice() + sage: V=IntegrableRepresentation(RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: V.weight_lattice() Extended weight lattice of the Root system of type ['E', 6, 1] """ return self._P @@ -221,8 +221,8 @@ def root_lattice(self): EXAMPLES:: - sage: v=IntegrableRepresentation(RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weight(0)) - sage: v.root_lattice() + sage: V=IntegrableRepresentation(RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: V.root_lattice() Root lattice of the Root system of type ['F', 4, 1] """ return self._Q @@ -253,8 +253,8 @@ def coxeter_number(self): EXAMPLES:: sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: v.coxeter_number() + sage: V = IntegrableRepresentation(Lambda[0]) + sage: V.coxeter_number() 12 """ return self._coxeter_number @@ -269,8 +269,8 @@ def dual_coxeter_number(self): EXAMPLES:: sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: v.dual_coxeter_number() + sage: V = IntegrableRepresentation(Lambda[0]) + sage: V.dual_coxeter_number() 9 """ return self._dual_coxeter_number @@ -294,8 +294,8 @@ def _latex_(self): EXAMPLES:: sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]+2*Lambda[3]) - sage: latex(v) + sage: V = IntegrableRepresentation(Lambda[0]+2*Lambda[3]) + sage: latex(V) B(\Lambda_{0} + 2\Lambda_{3}) """ return "B({})".format(self._Lam._latex_()) @@ -307,8 +307,8 @@ def cartan_type(self): EXAMPLES:: sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: v.cartan_type() + sage: V = IntegrableRepresentation(Lambda[0]) + sage: V.cartan_type() ['F', 4, 1] """ return self._cartan_type @@ -322,9 +322,9 @@ def _inner_qq(self, qelt1, qelt2): sage: P = RootSystem(['F',4,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: alpha = v.root_lattice().simple_roots() - sage: Matrix([[v._inner_qq(alpha[i], alpha[j]) for j in v._index_set] for i in v._index_set]) + sage: V = IntegrableRepresentation(Lambda[0]) + sage: alpha = V.root_lattice().simple_roots() + sage: Matrix([[V._inner_qq(alpha[i], alpha[j]) for j in V._index_set] for i in V._index_set]) [ 2 -1 0 0 0] [ -1 2 -1 0 0] [ 0 -1 2 -1 0] @@ -364,9 +364,9 @@ def _inner_pq(self, pelt, qelt): sage: P = RootSystem(['F',4,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: alpha = v.root_lattice().simple_roots() - sage: Matrix([[v._inner_pq(P(alpha[i]), alpha[j]) for j in v._index_set] for i in v._index_set]) + sage: V = IntegrableRepresentation(Lambda[0]) + sage: alpha = V.root_lattice().simple_roots() + sage: Matrix([[V._inner_pq(P(alpha[i]), alpha[j]) for j in V._index_set] for i in V._index_set]) [ 2 -1 0 0 0] [ -1 2 -1 0 0] [ 0 -1 2 -1 0] @@ -375,9 +375,9 @@ def _inner_pq(self, pelt, qelt): sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: alpha = v.root_lattice().simple_roots() - sage: Matrix([[v._inner_pq(Lambda[i],alpha[j]) for j in v._index_set] for i in v._index_set]) + sage: V = IntegrableRepresentation(Lambda[0]) + sage: alpha = V.root_lattice().simple_roots() + sage: Matrix([[V._inner_pq(Lambda[i],alpha[j]) for j in V._index_set] for i in V._index_set]) [ 1 0 0] [ 0 1/3 0] [ 0 0 1] @@ -396,13 +396,13 @@ def _inner_pp(self, pelt1, pelt2): sage: P = RootSystem(['G',2,1]).weight_lattice(extended=true) sage: Lambda = P.fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: alpha = v.root_lattice().simple_roots() - sage: Matrix([[v._inner_pp(Lambda[i],P(alpha[j])) for j in v._index_set] for i in v._index_set]) + sage: V = IntegrableRepresentation(Lambda[0]) + sage: alpha = V.root_lattice().simple_roots() + sage: Matrix([[V._inner_pp(Lambda[i],P(alpha[j])) for j in V._index_set] for i in V._index_set]) [ 1 0 0] [ 0 1/3 0] [ 0 0 1] - sage: Matrix([[v._inner_pp(Lambda[i],Lambda[j]) for j in v._index_set] for i in v._index_set]) + sage: Matrix([[V._inner_pp(Lambda[i],Lambda[j]) for j in V._index_set] for i in V._index_set]) [ 0 0 0] [ 0 2/3 1] [ 0 1 2] @@ -434,8 +434,8 @@ def to_weight(self, n): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[2]) - sage: v.to_weight((1,0,0)) + sage: V = IntegrableRepresentation(2*Lambda[2]) + sage: V.to_weight((1,0,0)) -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta """ alpha = self._P.simple_roots() @@ -463,11 +463,11 @@ def _from_weight_helper(self, mu, check=False): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[2]) - sage: v.to_weight((1,0,0)) + sage: V = IntegrableRepresentation(2*Lambda[2]) + sage: V.to_weight((1,0,0)) -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta - sage: delta = v.weight_lattice().null_root() - sage: v._from_weight_helper(2*Lambda[0] - Lambda[1] - 1*Lambda[2] + delta) + sage: delta = V.weight_lattice().null_root() + sage: V._from_weight_helper(2*Lambda[0] - Lambda[1] - 1*Lambda[2] + delta) (1, 0, 0) """ mu = self._P(mu) @@ -494,11 +494,11 @@ def from_weight(self, mu): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[2]) - sage: v.to_weight((1,0,0)) + sage: V = IntegrableRepresentation(2*Lambda[2]) + sage: V.to_weight((1,0,0)) -2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta - sage: delta = v.weight_lattice().null_root() - sage: v.from_weight(-2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta) + sage: delta = V.weight_lattice().null_root() + sage: V.from_weight(-2*Lambda[0] + Lambda[1] + 3*Lambda[2] - delta) (1, 0, 0) """ return self._from_weight_helper(self._Lam - mu) @@ -510,8 +510,8 @@ def s(self, n, i): EXAMPLES:: - sage: v = IntegrableRepresentation(RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weight(0)) - sage: [v.s((0,0,0),i) for i in v._index_set] + sage: V = IntegrableRepresentation(RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weight(0)) + sage: [V.s((0,0,0),i) for i in V._index_set] [(1, 0, 0), (0, 0, 0), (0, 0, 0)] """ ret = list(n) # This makes a copy @@ -527,10 +527,10 @@ def to_dominant(self, n): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(3*Lambda[0]) - sage: n = v.to_dominant((13,11,7)); n + sage: V = IntegrableRepresentation(3*Lambda[0]) + sage: n = V.to_dominant((13,11,7)); n (4, 3, 3) - sage: v.to_weight(n) + sage: V.to_weight(n) Lambda[0] + Lambda[1] + Lambda[2] - 4*delta """ if n in self._ddict: @@ -580,9 +580,9 @@ def _freudenthal_roots_imaginary(self, nu): EXAMPLES:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) - sage: [v._freudenthal_roots_imaginary(v.highest_weight() - mw) - ....: for mw in v.dominant_maximal_weights()] + sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: [V._freudenthal_roots_imaginary(V.highest_weight() - mw) + ....: for mw in V.dominant_maximal_weights()] [[], [], [], [], []] """ l = self._from_weight_helper(nu) @@ -602,9 +602,9 @@ def _freudenthal_roots_real(self, nu): EXAMPLES:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) - sage: mw = v.dominant_maximal_weights()[0] - sage: v._freudenthal_roots_real(v.highest_weight() - mw) + sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: mw = V.dominant_maximal_weights()[0] + sage: V._freudenthal_roots_real(V.highest_weight() - mw) [alpha[1], alpha[2], alpha[3], @@ -628,10 +628,10 @@ def _freudenthal_accum(self, nu, al): EXAMPLES:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) - sage: mw = v.dominant_maximal_weights()[0] - sage: F = v._freudenthal_roots_real(v.highest_weight() - mw) - sage: [v._freudenthal_accum(mw, al) for al in F] + sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: mw = V.dominant_maximal_weights()[0] + sage: F = V._freudenthal_roots_real(V.highest_weight() - mw) + sage: [V._freudenthal_accum(mw, al) for al in F] [4, 4, 3, 4, 3, 3] """ ret = 0 @@ -658,10 +658,10 @@ def _m_freudenthal(self, n): EXAMPLES:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) - sage: D = list(v.dominant_maximal_weights()) - sage: D.remove(v.highest_weight()) - sage: [v._m_freudenthal(v.from_weight(mw)) for mw in D] + sage: V = IntegrableRepresentation(Lambda[0]+Lambda[1]+Lambda[3]) + sage: D = list(V.dominant_maximal_weights()) + sage: D.remove(V.highest_weight()) + sage: [V._m_freudenthal(V.from_weight(mw)) for mw in D] [3, 7, 3, 3] """ if min(n) < 0: @@ -693,11 +693,11 @@ def m(self, n): EXAMPLES:: sage: Lambda = RootSystem(['E',6,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: u = v.highest_weight() - v.weight_lattice().null_root() - sage: v.from_weight(u) + sage: V = IntegrableRepresentation(Lambda[0]) + sage: u = V.highest_weight() - V.weight_lattice().null_root() + sage: V.from_weight(u) (1, 1, 2, 2, 3, 2, 1) - sage: v.m(v.from_weight(u)) + sage: V.m(V.from_weight(u)) 6 """ # TODO: Make this non-recursive by implementing our own stack @@ -772,10 +772,10 @@ def string(self, max_weight, depth=12): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: v.string(2*Lambda[0]) + sage: V = IntegrableRepresentation(2*Lambda[0]) + sage: V.string(2*Lambda[0]) [1, 2, 8, 20, 52, 116, 256, 522, 1045, 1996, 3736, 6780] - sage: v.string(Lambda[1] + Lambda[2]) + sage: V.string(Lambda[1] + Lambda[2]) [0, 1, 4, 12, 32, 77, 172, 365, 740, 1445, 2736, 5041] """ ret = [] @@ -799,8 +799,8 @@ def strings(self, depth=12): EXAMPLES:: sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: S = v.strings(depth=25) + sage: V = IntegrableRepresentation(2*Lambda[0]) + sage: S = V.strings(depth=25) sage: for k in S: ....: print "{}: {}".format(k, ' '.join(str(x) for x in S[k])) 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 @@ -820,8 +820,8 @@ def print_strings(self, depth=12): EXAMPLES:: sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: v.print_strings(depth=25) + sage: V = IntegrableRepresentation(2*Lambda[0]) + sage: V.print_strings(depth=25) 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ @@ -863,8 +863,8 @@ def modular_characteristic(self, mu=None): EXAMPLES:: sage: Lambda = RootSystem(['A',1,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(3*Lambda[0]+2*Lambda[1]) - sage: [v.modular_characteristic(x) for x in v.dominant_maximal_weights()] + sage: V = IntegrableRepresentation(3*Lambda[0]+2*Lambda[1]) + sage: [V.modular_characteristic(x) for x in V.dominant_maximal_weights()] [11/56, -1/280, 111/280] """ if type(mu) is tuple: @@ -914,8 +914,8 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): EXAMPLES:: sage: Lambda = RootSystem(['A',2,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(2*Lambda[0]) - sage: b = v.branch(); b + sage: V = IntegrableRepresentation(2*Lambda[0]) + sage: b = V.branch(); b [A2(0,0), A2(1,1), A2(0,0) + 2*A2(1,1) + A2(2,2), @@ -933,8 +933,8 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): are branching to. This is determined by the Dynkin diagram:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: v.cartan_type().dynkin_diagram() + sage: V = IntegrableRepresentation(Lambda[0]) + sage: V.cartan_type().dynkin_diagram() O 0 | | @@ -948,7 +948,7 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): `\mathfrak{sl}(2) \times \mathfrak{sl}(2) \times \mathfrak{sl}(2)`:: sage: A1xA1xA1 = WeylCharacterRing("A1xA1xA1",style="coroots") - sage: v.branch(i=2,weyl_character_ring=A1xA1xA1) + sage: V.branch(i=2,weyl_character_ring=A1xA1xA1) [A1xA1xA1(1,0,0), A1xA1xA1(0,1,2), A1xA1xA1(1,0,0) + A1xA1xA1(1,2,0) + A1xA1xA1(1,0,2), @@ -963,8 +963,8 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): EXAMPLES:: sage: Lambda = RootSystem(['F',4,1]).weight_lattice(extended=true).fundamental_weights() - sage: v = IntegrableRepresentation(Lambda[0]) - sage: v.cartan_type().dynkin_diagram() + sage: V = IntegrableRepresentation(Lambda[0]) + sage: V.cartan_type().dynkin_diagram() O---O---O=>=O---O 0 1 2 3 4 F4~ @@ -981,7 +981,7 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): The nodes `0, 2, 3, 4` of ``F4~`` correspond to ``1, 4, 3, 2`` of ``A1xC3`` and so we encode this in a dictionary:: - sage: v.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) # long time + sage: V.branch(i=1,weyl_character_ring=A1xC3,sequence={0:1,2:4,3:3,4:2}) # long time [A1xC3(1,0,0,0), A1xC3(0,0,0,1), A1xC3(1,0,0,0) + A1xC3(1,2,0,0), From 39d98d9df53aaa6e3fdf899ec5fed8619fb74ce0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 24 Apr 2015 11:14:53 -0700 Subject: [PATCH 517/665] Fixing notation and documentation. --- .../root_system/integrable_representations.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index b5623276a03..2bb8a182a36 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -35,25 +35,26 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): .. [Kac] Kac, *Infinite-dimensional Lie algebras*, Third Edition. Cambridge, 1990. - .. [KMPS] Kass, Moody, Patera and Slansky, Affine Lie algebras, - weight multiplicities, and branching rules. Vols. 1, 2. University of - California Press, Berkeley, CA, 1990. + .. [KMPS] Kass, Moody, Patera and Slansky, *Affine Lie algebras, + weight multiplicities, and branching rules*. Vols. 1, 2. University + of California Press, Berkeley, CA, 1990. - .. [KacPeterson] Kac and Peterson. Infinite-dimensional Lie algebras, theta - functions and modular forms. Adv. in Math. 53 (1984), no. 2, 125-264. + .. [KacPeterson] Kac and Peterson. *Infinite-dimensional Lie algebras, + theta functions and modular forms*. Adv. in Math. 53 (1984), + no. 2, 125-264. If `\Lambda` is a dominant integral weight for an affine root system, there exists a unique integrable representation `V=V_\Lambda` of highest weight `\Lambda`. If `\mu` is another weight, let `m(\mu)` denote the multiplicity of the weight `\mu` in this representation. The set - `\text{supp}(V)` of `\mu` such that `m(\mu)>0` is contained in the + `\operatorname{supp}(V)` of `\mu` such that `m(\mu) > 0` is contained in the paraboloid .. MATH:: (\Lambda+\rho | \Lambda+\rho) - (\mu+\rho | \mu+\rho) \geq 0 - where `(\,|\,)` is the invariant inner product on the weight + where `(\, | \,)` is the invariant inner product on the weight lattice and `\rho` is the Weyl vector. Moreover every `\mu` differs from `\Lambda` by an element of the root lattice. ([Kac]_, Propositions 11.3 and 11.4) such that `\Lambda - \mu` is in the root lattice, then @@ -232,7 +233,7 @@ def level(self): """ Return the level of ``self``. - The level of a highest weight representation `B(\Lambda)` is + The level of a highest weight representation `V_{\Lambda}` is defined as `(\Lambda | \delta)` See [Kac]_ section 12.4. EXAMPLES:: @@ -296,9 +297,9 @@ def _latex_(self): sage: Lambda = RootSystem(['C',3,1]).weight_lattice(extended=true).fundamental_weights() sage: v = IntegrableRepresentation(Lambda[0]+2*Lambda[3]) sage: latex(v) - B(\Lambda_{0} + 2\Lambda_{3}) + V_{\Lambda_{0} + 2\Lambda_{3}} """ - return "B({})".format(self._Lam._latex_()) + return "V_{{{}}}".format(self._Lam._latex_()) def cartan_type(self): """ From dbdfa4c3f97fe7dc9eb9493ee4d2ec590e22a113 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 24 Apr 2015 12:23:54 -0700 Subject: [PATCH 518/665] doc revision --- .../root_system/integrable_representations.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 28ca8b8240a..97e0d079773 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -892,11 +892,11 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): removing the `0` node from the Dynkin diagram of type ``[X, r, 1]`` produces the classical Dynkin diagram of ``[X, r]``. - Thus for each `i` in the index set, we may restrict `self` to - the corresponding classical subalgebra. Of course `self` is + Thus for each `i` in the index set, we may restrict ``self`` to + the corresponding classical subalgebra. Of course ``self`` is an infinite dimensional representation, but each weight `\mu` is assigned a grading by the number of times the simple root - `\\alpha_i` appears in `\Lambda-\mu`. Thus the branched + `\alpha_i` appears in `\Lambda-\mu`. Thus the branched representation is graded and we get sequence of finite-dimensional representations which this method is able to compute. @@ -924,13 +924,13 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): 4*A2(0,0) + 3*A2(0,3) + 10*A2(1,1) + 3*A2(3,0) + A2(1,4) + 6*A2(2,2) + A2(4,1), 6*A2(0,0) + 9*A2(0,3) + 20*A2(1,1) + 9*A2(3,0) + 3*A2(1,4) + 12*A2(2,2) + 3*A2(4,1) + A2(3,3)] - If the parameter weyl_character_ring is omitted, the ring may be recovered + If the parameter ``weyl_character_ring`` is omitted, the ring may be recovered as the parent of one of the branched coefficients:: sage: A2 = b[0].parent(); A2 The Weyl Character Ring of Type A2 with Integer Ring coefficients - If `i` is not zero then you should specify the WeylCharacterRing that you + If `i` is not zero then you should specify the :class:`WeylCharacterRing` that you are branching to. This is determined by the Dynkin diagram:: sage: Lambda = RootSystem(['B',3,1]).weight_lattice(extended=true).fundamental_weights() @@ -990,6 +990,15 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): 2*A1xC3(1,0,0,0) + A1xC3(1,0,1,0) + 2*A1xC3(1,2,0,0) + A1xC3(1,0,2,0) + A1xC3(3,0,0,0), 2*A1xC3(2,0,0,1) + A1xC3(2,1,1,0) + A1xC3(0,1,0,0) + 3*A1xC3(0,0,0,1) + 2*A1xC3(0,1,1,0) + A1xC3(0,2,0,1)] + The branch method gives a way of computing the graded dimension of the integrable representation:: + + sage: Lambda = RootSystem("A1~").weight_lattice(extended=true).fundamental_weights() + sage: V=IntegrableRepresentation(Lambda[0]) + sage: r = [x.degree() for x in V.branch(depth=15)]; r + [1, 3, 4, 7, 13, 19, 29, 43, 62, 90, 126, 174, 239, 325, 435, 580] + sage: oeis(r) + 0: A029552: Expansion of phi(x) / f(-x) in powers of x where phi(), f() are Ramanujan theta functions. + """ if i is None: i = self._cartan_type.special_node() From ca5ccc2eb20d9c63e27d9a78054cd38d48590088 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Fri, 24 Apr 2015 16:04:56 -0700 Subject: [PATCH 519/665] oeis test is optional --- src/sage/combinat/root_system/integrable_representations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 97e0d079773..2add6b426e0 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -996,7 +996,7 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): sage: V=IntegrableRepresentation(Lambda[0]) sage: r = [x.degree() for x in V.branch(depth=15)]; r [1, 3, 4, 7, 13, 19, 29, 43, 62, 90, 126, 174, 239, 325, 435, 580] - sage: oeis(r) + sage: oeis(r) # optional -- internet 0: A029552: Expansion of phi(x) / f(-x) in powers of x where phi(), f() are Ramanujan theta functions. """ From 933c5c587943027944e226bc3b3b80181f22e967 Mon Sep 17 00:00:00 2001 From: Dmitrii Pasechnik Date: Sat, 25 Apr 2015 01:34:28 +0100 Subject: [PATCH 520/665] merged patch files, renamed... --- ...{gmp-h_in.patch => gcc49_workaround.patch} | 11 +++++ build/pkgs/mpir/patches/mpir_fat_binary.patch | 44 ------------------- 2 files changed, 11 insertions(+), 44 deletions(-) rename build/pkgs/mpir/patches/{gmp-h_in.patch => gcc49_workaround.patch} (71%) delete mode 100644 build/pkgs/mpir/patches/mpir_fat_binary.patch diff --git a/build/pkgs/mpir/patches/gmp-h_in.patch b/build/pkgs/mpir/patches/gcc49_workaround.patch similarity index 71% rename from build/pkgs/mpir/patches/gmp-h_in.patch rename to build/pkgs/mpir/patches/gcc49_workaround.patch index 69854f19ee5..73af5dba011 100644 --- a/build/pkgs/mpir/patches/gmp-h_in.patch +++ b/build/pkgs/mpir/patches/gcc49_workaround.patch @@ -21,3 +21,14 @@ #include /* for size_t */ #endif #undef __need_size_t +--- src/mpirxx.h ++++ src/mpirxx.h +@@ -32,6 +32,8 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ + #ifndef __GMP_PLUSPLUS__ + #define __GMP_PLUSPLUS__ + ++#include /* for size_t */ ++ + #include + + #include /* for strlen */ diff --git a/build/pkgs/mpir/patches/mpir_fat_binary.patch b/build/pkgs/mpir/patches/mpir_fat_binary.patch deleted file mode 100644 index 20460ead079..00000000000 --- a/build/pkgs/mpir/patches/mpir_fat_binary.patch +++ /dev/null @@ -1,44 +0,0 @@ -# see trac 17806: MPIR fails to build on 32-bit Linux with SAGE_FAT_BINARY=yes ---- src/mpn/x86/fat/fat.c -+++ src/mpn/x86/fat/fat.c -@@ -37,6 +37,8 @@ MA 02110-1301, USA. */ - long __gmpn_cpuid __GMP_PROTO ((char dst[12], int id)); - - struct cpuvec_t __gmpn_cpuvec = { -+ __MPN(add_err1_n_init), -+ __MPN(add_err2_n_init), - __MPN(add_n_init), - __MPN(addmul_1_init), - __MPN(copyd_init), -@@ -55,11 +57,14 @@ struct cpuvec_t __gmpn_cpuvec = { - __MPN(modexact_1c_odd_init), - __MPN(mul_1_init), - __MPN(mul_basecase_init), -+ __MPN(mulmid_basecase_init), - __MPN(preinv_divrem_1_init), - __MPN(preinv_mod_1_init), - __MPN(redc_1_init), - __MPN(rshift_init), - __MPN(sqr_basecase_init), -+ __MPN(sub_err1_n_init), -+ __MPN(sub_err2_n_init), - __MPN(sub_n_init), - __MPN(submul_1_init), - __MPN(sumdiff_n_init), -@@ -102,6 +107,8 @@ struct cpuvec_t __gmpn_cpuvec = { - #define CPUSETUP_nehalem CPUVEC_SETUP_nehalem - #define CPUSETUP_westmere CPUVEC_SETUP_nehalem - #define CPUSETUP_sandybridge CPUVEC_SETUP_nehalem -+#define CPUSETUP_ivybridge CPUVEC_SETUP_nehalem -+#define CPUSETUP_haswell CPUVEC_SETUP_nehalem - #define CPUSETUP_atom CPUVEC_SETUP_p6;CPUVEC_SETUP_p6_mmx;CPUVEC_SETUP_p6_p3mmx - #define CPUSETUP_nano CPUVEC_SETUP_p6;CPUVEC_SETUP_p6_mmx;CPUVEC_SETUP_p6_p3mmx - #define CPUSETUP_pentium4 CPUVEC_SETUP_pentium4;CPUVEC_SETUP_pentium4_mmx;CPUVEC_SETUP_pentium4_sse2 -@@ -116,6 +123,7 @@ struct cpuvec_t __gmpn_cpuvec = { - #define CPUSETUP_k102 CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 - #define CPUSETUP_k103 CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 - #define CPUSETUP_bulldozer CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 -+#define CPUSETUP_piledriver CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 - #define CPUSETUP_bobcat CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 - #define CPUSETUP_viac3 do{}while(0) - #define CPUSETUP_viac32 do{}while(0) From c089c09c551d50ec9b4cbd9889f74f631ef12f61 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 24 Apr 2015 22:46:36 -0400 Subject: [PATCH 521/665] Added random element functions to Semistandard Tableaux --- src/sage/combinat/tableau.py | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 4f06a222bf9..f09bcd677c0 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5053,6 +5053,48 @@ def __contains__(self, x): return SemistandardTableaux.__contains__(self, x) \ and sum(map(len,x)) == self.size and max(flatten(x)) <= self.max_entry + def random_element(self): + """ + Generate a random ``SemistandardTableau`` with uniform probability. + + The RSK algorithm gives a bijection between symmetric `k\times k` matrices + of nonnegative integers that sum to `n` and semistandard tableaux with size `n` + and maximum entry `k`. + + To generate a random symmetric matrix with a given sum, we first choose the trace of the + matrix + + TESTS:: + + sage: SemistandardTableaux(6, max_entry=7).random_element() + [[2, 2], [3, 3], [6, 6]] + + """ + from sage.rings.all import ZZ + from sage.rings.arith import binomial + from sage.matrix.constructor import diagonal_matrix + from sage.combinat.rsk import RSK + kchoose2m1 = self.max_entry * (self.max_entry - 1) / 2 - 1 + km1 = self.max_entry - 1 + weights = [binomial(self.size - i + km1, km1) * binomial((i/2) + kchoose2m1, kchoose2m1) + for i in range(0, self.size + 1, 2)] + randpos = ZZ.random_element(sum(weights)) + tot = weights[0] + pos = 0 + while (randpos >= tot): + pos += 1 + tot += weights[pos] + # we now have pos elements over the diagonal and n - 2 * pos on it + m = diagonal_matrix(IntegerVectors(self.size - 2 * pos, self.max_entry).random_element()) + above_diagonal = IntegerVectors(pos, kchoose2m1 + 1).random_element() + index = 0 + for i in range(self.max_entry - 1): + for j in range(i + 1, self.max_entry): + m[i,j] = above_diagonal[index] + m[j,i] = above_diagonal[index] + index += 1 + return RSK(m)[0] + def cardinality(self): """ Return the cardinality of ``self``. @@ -5238,6 +5280,55 @@ def _repr_(self): """ return "Semistandard tableaux of shape %s and maximum entry %s" %(str(self.shape), str(self.max_entry)) + def random_element(self): + """ + Returns a uniformly distributed random tableau of the given shape and max_entry. + + Uses the algorithm from [Krat99] based on the Novelli-Pak-Stoyanovskii bijection + + TESTS:: + + sage: SemistandardTableaux([2, 2, 1, 1], max_entry=7).random_element() + [[1, 2], [2, 4], [3], [5]] + + + REFERENCES: + + .. [Krat99] C. Krattenthaler, + *Another Involution Principle-Free Bijective Proof of Stanley's Hook Content Formula*, + Journal of Combinatorial Theory, Series A vol 88 Issue 1 (1999), 66-92, + http://www.sciencedirect.com/science/article/pii/0012365X9290368P + """ + from sage.misc.prandom import randint + from sage.combinat.partition import Partition + with_sentinels = [max(i,j) for i,j in zip([0]+list(self.shape), [k+1 for k in self.shape]+[0])] + t = [[self.max_entry+1]*i for i in with_sentinels] + for i,l in enumerate(self.shape): + for j in range(l): + content = j - i + t[i][j] = randint(1 - content, self.max_entry) + conj = Partition(self.shape).conjugate() + for i in xrange(len(conj) - 1, -1, -1): + for j in xrange(conj[i] - 1, -1, -1): + row = j + col = i + s = t[row][col] + x = t[row][col + 1] + y = t[row + 1][col] + while s > x or s >= y: + if x + 1 < y: + t[row][col] = x + 1 + t[row][col + 1] = s + col += 1 + else: + t[row][col] = y - 1 + t[row + 1][col] = s + row += 1 + x = t[row][col + 1] + y = t[row + 1][col] + return SemistandardTableau([l[:c] for l,c in zip(t, self.shape)]) + + def cardinality(self): """ Returns the cardinality of ``self``. From 6785ef2000d220f511fcf3e9830b05099500ef47 Mon Sep 17 00:00:00 2001 From: Dmitrii Pasechnik Date: Sat, 25 Apr 2015 07:03:22 +0100 Subject: [PATCH 522/665] restored wrongly removed file, and deleted one that should have gone --- build/pkgs/mpir/patches/mpir_fat_binary.patch | 44 +++++++++++++++++++ build/pkgs/mpir/patches/mpirxx_h.patch | 12 ----- 2 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 build/pkgs/mpir/patches/mpir_fat_binary.patch delete mode 100644 build/pkgs/mpir/patches/mpirxx_h.patch diff --git a/build/pkgs/mpir/patches/mpir_fat_binary.patch b/build/pkgs/mpir/patches/mpir_fat_binary.patch new file mode 100644 index 00000000000..20460ead079 --- /dev/null +++ b/build/pkgs/mpir/patches/mpir_fat_binary.patch @@ -0,0 +1,44 @@ +# see trac 17806: MPIR fails to build on 32-bit Linux with SAGE_FAT_BINARY=yes +--- src/mpn/x86/fat/fat.c ++++ src/mpn/x86/fat/fat.c +@@ -37,6 +37,8 @@ MA 02110-1301, USA. */ + long __gmpn_cpuid __GMP_PROTO ((char dst[12], int id)); + + struct cpuvec_t __gmpn_cpuvec = { ++ __MPN(add_err1_n_init), ++ __MPN(add_err2_n_init), + __MPN(add_n_init), + __MPN(addmul_1_init), + __MPN(copyd_init), +@@ -55,11 +57,14 @@ struct cpuvec_t __gmpn_cpuvec = { + __MPN(modexact_1c_odd_init), + __MPN(mul_1_init), + __MPN(mul_basecase_init), ++ __MPN(mulmid_basecase_init), + __MPN(preinv_divrem_1_init), + __MPN(preinv_mod_1_init), + __MPN(redc_1_init), + __MPN(rshift_init), + __MPN(sqr_basecase_init), ++ __MPN(sub_err1_n_init), ++ __MPN(sub_err2_n_init), + __MPN(sub_n_init), + __MPN(submul_1_init), + __MPN(sumdiff_n_init), +@@ -102,6 +107,8 @@ struct cpuvec_t __gmpn_cpuvec = { + #define CPUSETUP_nehalem CPUVEC_SETUP_nehalem + #define CPUSETUP_westmere CPUVEC_SETUP_nehalem + #define CPUSETUP_sandybridge CPUVEC_SETUP_nehalem ++#define CPUSETUP_ivybridge CPUVEC_SETUP_nehalem ++#define CPUSETUP_haswell CPUVEC_SETUP_nehalem + #define CPUSETUP_atom CPUVEC_SETUP_p6;CPUVEC_SETUP_p6_mmx;CPUVEC_SETUP_p6_p3mmx + #define CPUSETUP_nano CPUVEC_SETUP_p6;CPUVEC_SETUP_p6_mmx;CPUVEC_SETUP_p6_p3mmx + #define CPUSETUP_pentium4 CPUVEC_SETUP_pentium4;CPUVEC_SETUP_pentium4_mmx;CPUVEC_SETUP_pentium4_sse2 +@@ -116,6 +123,7 @@ struct cpuvec_t __gmpn_cpuvec = { + #define CPUSETUP_k102 CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 + #define CPUSETUP_k103 CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 + #define CPUSETUP_bulldozer CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 ++#define CPUSETUP_piledriver CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 + #define CPUSETUP_bobcat CPUVEC_SETUP_k7;CPUVEC_SETUP_k7_mmx;CPUVEC_SETUP_k7_mmx_k8;CPUVEC_SETUP_k7_mmx_k8_k10;CPUVEC_SETUP_k7_mmx_k8_k10_k102 + #define CPUSETUP_viac3 do{}while(0) + #define CPUSETUP_viac32 do{}while(0) diff --git a/build/pkgs/mpir/patches/mpirxx_h.patch b/build/pkgs/mpir/patches/mpirxx_h.patch deleted file mode 100644 index 62682433fc4..00000000000 --- a/build/pkgs/mpir/patches/mpirxx_h.patch +++ /dev/null @@ -1,12 +0,0 @@ -# porting to gcc 4.9; see #18240 ---- src/mpirxx.h -+++ src/mpirxx.h -@@ -32,6 +32,8 @@ along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ - #ifndef __GMP_PLUSPLUS__ - #define __GMP_PLUSPLUS__ - -+#include /* for size_t */ -+ - #include - - #include /* for strlen */ From f85548eccd9accc367a868e26ce3b783a2b1cb1e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 24 Apr 2015 23:14:17 -0700 Subject: [PATCH 523/665] Fixing my stupid typo and not checking. --- src/sage/combinat/ncsf_qsym/qsym.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 40437ab13c2..e481a207a31 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -2093,7 +2093,7 @@ def to_symmetric_function(self): We check that the result is indexed by partitions:: sage: M([]).to_symmetric_function().leading_support().parent() - Parittions + Partitions """ m = SymmetricFunctions(self.parent().base_ring()).monomial() if self.is_symmetric(): From 23dea68c64c8fb1e5957d6396bb0f98c4fa850d1 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 24 Apr 2015 23:22:06 -0700 Subject: [PATCH 524/665] Some documentation tweaks per Darij's comment. --- src/sage/combinat/sf/macdonald.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 29b3b105e62..21e989c24a0 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -637,8 +637,8 @@ def cmunu1(mu, nu): True """ q,t = QQqt.gens() - # The following for loop is equivalent to: - # r,c = SkewPartition([mu,nu]).cells()[0] + # The following for loop is equivalent to getting the cell: + # SkewPartition([mu,nu]).cells()[0] for i, val in enumerate(nu._list): if val < mu._list[i]: A = prod((t**mu.leg_length(i, s) - q**(mu.arm_length(i, s)+1)) @@ -927,13 +927,17 @@ class Element(sfa.SymmetricFunctionAlgebra_generic.Element): def nabla(self, q=None, t=None, power=1): r""" - Returns the value of the nabla operator applied to ``self``. The - eigenvectors of the nabla operator are the Macdonald polynomials in - the `Ht` basis. For more information see: [BGHT1999]_. + Return the value of the nabla operator applied to ``self``. + + The eigenvectors of the nabla operator are the Macdonald + polynomials in the `Ht` basis. For more information + see: [BGHT1999]_. The operator nabla acts on symmetric functions and has the Macdonald `Ht` basis as eigenfunctions and the eigenvalues - are `q^{n(\mu')} t^{n(\mu)}` where `n(\mu) = \sum_{i} (i-1) \mu_i`. + are `q^{n(\mu')} t^{n(\mu)}` where + `n(\mu) = \sum_{i} (i-1) \mu_i` and `\mu'` is the conjugate + shape of `\mu`. If the parameter ``power`` is an integer then it calculates nabla to that integer. The default value of ``power`` is 1. From bf7c96032b7c50a62cae57fa4c7fb8ae6368a0be Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 24 Apr 2015 23:35:30 -0700 Subject: [PATCH 525/665] Changes to the catalog. --- src/sage/algebras/catalog.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 8a298d50b21..88a30534497 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -20,6 +20,7 @@ ` - :class:`algebras.Group ` - :class:`algebras.Hall ` +- :class:`algebras.Incidence ` - :class:`algebras.IwahoriHecke ` - :class:`algebras.NilCoxeter @@ -46,5 +47,6 @@ lazy_import('sage.algebras.hall_algebra', 'HallAlgebra', 'Hall') lazy_import('sage.algebras.shuffle_algebra', 'ShuffleAlgebra', 'Shuffle') lazy_import('sage.algebras.commutative_dga', 'GradedCommutativeAlgebra', 'GradedCommutative') +lazy_import('sage.combinat.posets.incidence_algebras', 'IncidenceAlgebra', 'Incidence') del lazy_import # We remove the object from here so it doesn't appear under tab completion From c1a07e29756c21fba61ef02aa762bf19afd1b962 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 24 Apr 2015 23:57:20 -0700 Subject: [PATCH 526/665] Tweaks to the documentation and code. --- src/sage/combinat/tableau.py | 42 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 0d9cbb2b498..c70ad0c2964 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5350,26 +5350,27 @@ def _repr_(self): def cardinality(self, algorithm='hook'): r""" - Returns the cardinality of ``self``. + Return the cardinality of ``self``. - INPUT: - - ``algorithm`` -- (Default: ``'hook'``) any one of the following: + - ``algorithm`` -- (default: ``'hook'``) any one of the following: - - ``'hook'`` -- Use Stanley's hook formula + - ``'hook'`` -- use Stanley's hook length formula - - ``'sum'`` -- Sum over the compositions of ``max_entry`` the number of semistandard tableau with ``shape`` and given weight vector. + - ``'sum'`` -- sum over the compositions of ``max_entry`` the + number of semistandard tableau with ``shape`` and given + weight vector - This is computed using *Stanley's hook length formula* + This is computed using *Stanley's hook length formula*: .. MATH:: + f_{\lambda} = \prod_{u\in\lambda} \frac{n+c(u)}{h(u)}. - where `n` is the ``max_entry``, `c(u)` is the content of `u` and `h(u)` is the hook length - of `u`. - - See [Sta99] Corollary 7.21.4. + where `n` is the ``max_entry``, `c(u)` is the content of `u`, + and `h(u)` is the hook length of `u`. + See [Sta-EC2]_ Corollary 7.21.4. EXAMPLES:: @@ -5388,32 +5389,25 @@ def cardinality(self, algorithm='hook'): sage: SemistandardTableaux([6,5,4,3,2,1], max_entry=30).cardinality() 208361017592001331200 sage: ssts = [SemistandardTableaux(p, max_entry=6) for p in Partitions(5)] - sage: all(sst.cardinality() == sst.cardinality(algorithm='sum') for sst in ssts) + sage: all(sst.cardinality() == sst.cardinality(algorithm='sum') + ....: for sst in ssts) True - - - REFERENCES: - - .. [Sta99] Stanley, Richard. - Enumerative Combinatorics, Vol. 2. - Cambridge University Press, 1999 - """ if algorithm == 'hook': conj = self.shape.conjugate() - num = 1 - den = 1 + num = Integer(1) + den = Integer(1) for i,l in enumerate(self.shape): for j in range(l): - num *= (self.max_entry + j -i) - den *= (l + conj[j] - i - j - 1) + num *= self.max_entry + j - i + den *= l + conj[j] - i - j - 1 return Integer(num / den) elif algorithm == 'sum': c = 0 for comp in IntegerVectors(sum(self.shape), self.max_entry): c += SemistandardTableaux_shape_weight(self.shape, Composition(comp)).cardinality() return c - raise ValueError("unknown algorithm %r" % algorithm) + raise ValueError("unknown algorithm {}".format(algorithm)) class SemistandardTableaux_shape_weight(SemistandardTableaux_shape): r""" From 8e7824dc463fccee32c14818d700ea1d58de5962 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 25 Apr 2015 00:09:04 -0700 Subject: [PATCH 527/665] Removing trailing whitespace. --- src/sage/combinat/tableau.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index c70ad0c2964..15dea328d19 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5371,7 +5371,7 @@ def cardinality(self, algorithm='hook'): where `n` is the ``max_entry``, `c(u)` is the content of `u`, and `h(u)` is the hook length of `u`. See [Sta-EC2]_ Corollary 7.21.4. - + EXAMPLES:: sage: SemistandardTableaux([2,1]).cardinality() From 92b276a18e65b99d8a5bb85f2d22ddf976fb9020 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:34:01 +0200 Subject: [PATCH 528/665] games.hexad: rst fixes --- src/sage/games/hexad.py | 177 ++++++++++++++++++++++++---------------- 1 file changed, 107 insertions(+), 70 deletions(-) diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index eab3d568793..980a491cfe2 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -1,18 +1,18 @@ r""" Hexads in S(5,6,12) - This module completes a 5-element subset of as 12-set X - into a hexad in a Steiner system S(5,6,12) using Curtis and - Conway's "kitten method". The labeling is either the - "modulo 11" labeling or the "shuffle" labeling. +This module completes a 5-element subset of as 12-set X +into a hexad in a Steiner system S(5,6,12) using Curtis and +Conway's "kitten method". The labeling is either the +"modulo 11" labeling or the "shuffle" labeling. - The main functions implemented in this file are - blackjack_move and find_hexad. Enter "blackjack_move?" - for help to play blackjack (i.e., the rules of the game), or - "find_hexad?" for help finding hexads of S(5,6,12) in the - shuffle labeling. +The main functions implemented in this file are +blackjack_move and find_hexad. Enter "blackjack_move?" +for help to play blackjack (i.e., the rules of the game), or +"find_hexad?" for help finding hexads of S(5,6,12) in the +shuffle labeling. - This picture is the kitten in the "shuffle" labeling: +This picture is the kitten in the "shuffle" labeling:: 6 @@ -30,7 +30,7 @@ 1 0 -The corresponding MINIMOG is +The corresponding MINIMOG is:: _________________ | 6 | 3 | 0 | 9 | @@ -44,21 +44,26 @@ See the docstrings for find_hexad and blackjack_move for further details and examples. -AUTHOR:: - David Joyner (2006-05) +AUTHOR: -REFERENCES:: - R. Curtis, ``The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, - and the kitten,'' in {\bf Computational group theory}, ed. M. Atkinson, - Academic Press, 1984. - J. Conway, ``Hexacode and tetracode - MINIMOG and MOG,'' in {\bf Computational - group theory}, ed. M. Atkinson, Academic Press, 1984. - J. Conway and N. Sloane, ``Lexicographic codes: error-correcting codes from - game theory,'' IEEE Trans. Infor. Theory32(1986)337-348. - J. Kahane and A. Ryba, ``The hexad game,'' Electronic Journal of Combinatorics, 8 (2001) - http://www.combinatorics.org/Volume_8/Abstracts/v8i2r11.html +David Joyner (2006-05) - Some details are also online at: http://www.permutationpuzzles.org/hexad/ +REFERENCES: + +R. Curtis, The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, +and the kitten, in *Computational group theory*, ed. M. Atkinson, +Academic Press, 1984. + +J. Conway, Hexacode and tetracode - MINIMOG and MOG, in *Computational +group theory*, ed. M. Atkinson, Academic Press, 1984. + +J. Conway and N. Sloane, *Lexicographic codes: error-correcting codes from +game theory*, IEEE Trans. Infor. Theory 32 (1986) 337-348. + +J. Kahane and A. Ryba, The hexad game, *Electronic Journal of Combinatorics*, 8 (2001) +http://www.combinatorics.org/Volume_8/Abstracts/v8i2r11.html + +Some details are also online at: http://www.permutationpuzzles.org/hexad/ """ #***************************************************************************** @@ -86,6 +91,7 @@ def view_list(L): as in Curtis' paper. EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: view_list(M.line[1]) @@ -118,6 +124,7 @@ def picture_set(A,L): This is needed in the find_hexad function below. EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: picture_set(M.picture00, M.cross[2]) @@ -134,6 +141,7 @@ class Minimog(): triple system S(5,6,12). EXAMPLES:: + sage: from sage.games.hexad import * sage: Minimog(type="shuffle") Minimog of type shuffle @@ -230,6 +238,7 @@ def __str__(self): """ EXAMPLES:: + sage: M = Minimog(type="modulo11") sage: print M Minimog of type modulo11 associated to @@ -245,6 +254,7 @@ def _latex_(self): Prints latex code. EXAMPLES:: + sage: M = Minimog(type="modulo11") sage: latex(M) Minimog of type modulo11 associated to @@ -263,6 +273,7 @@ def print_kitten(self): of symbols). EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog("shuffle") sage: M.print_kitten() @@ -304,15 +315,21 @@ def print_kitten(self): def find_hexad0(self, pts): """ - INPUT:: - pts -- a set of 2 distinct elements of MINIMOG, but not - including the "points at infinity" - OUTPUT:: - hexad containing pts and of type 0 (the 3 points "at infinity" union a line) + INPUT: + + - pts -- a set of 2 distinct elements of MINIMOG, but not including the + "points at infinity" + + OUTPUT: + + - hexad containing pts and of type 0 (the 3 points "at infinity" union a line) + + NOTE: - NOTE:: 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: M.find_hexad0(set([2,4])) @@ -339,15 +356,19 @@ def find_hexad0(self, pts): def find_hexad1(self, pts): """ - INPUT:: - pts -- a set pts of 5 distinct elements of MINIMOG - OUTPUT:: - hexad containing pts and of type 1 (union of 2 parallel lines -- *no* - points "at infinity") + INPUT: + + pts -- a set pts of 5 distinct elements of MINIMOG + + OUTPUT: + + hexad containing pts and of type 1 (union of 2 parallel lines -- *no* + points "at infinity") - NOTE:: 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + NOTE: 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: M.find_hexad1(set([2,3,4,5,8])) @@ -376,15 +397,18 @@ def find_hexad1(self, pts): def find_hexad2(self, pts, x0): """ - INPUT:: - pts -- a list S of 4 elements of MINIMOG, not including - any "points at infinity" - x0 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + INPUT: + + - pts -- a list S of 4 elements of MINIMOG, not including any "points + at infinity" + - x0 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + + OUTPUT: - OUTPUT:: - hexad containing S \union \{x0\} of type 2 + hexad containing `S \union \{x0\}` of type 2 EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: M.find_hexad2([2,3,4,5],1) @@ -417,16 +441,19 @@ def find_hexad2(self, pts, x0): def find_hexad3(self, pts, x0, x1): """ - INPUT:: - pts -- a list of 3 elements of MINIMOG, not including - any "points at infinity" - x0,x1 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + INPUT: + + - pts -- a list of 3 elements of MINIMOG, not including any "points at + infinity" + - x0,x1 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} - OUTPUT:: - hexad containing pts \union \{x0,x1\} of type 3 (square at - picture of "omitted point at infinity") + OUTPUT: + + hexad containing pts \union \{x0,x1\} of type 3 (square at + picture of "omitted point at infinity") EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: M.find_hexad3([2,3,4],0,1) @@ -453,24 +480,29 @@ def find_hexad3(self, pts, x0, x1): def find_hexad(self, pts): """ - INPUT:: - pts -- a list S of 5 elements of MINIMOG + INPUT: + + pts -- a list S of 5 elements of MINIMOG - OUTPUT:: - hexad containing S \union \{x0\} of some type + OUTPUT: - NOTE:: 3 "points at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} + hexad containing $S \union \{x0\}$ of some type + + NOTE: 3 "points at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} Theorem (Curtis, Conway): Each hexads is of exactly one of the following types: - 0. $\{3 ``points at infinity''\}\cup \{{\rm any\ line}\}$, - 1. the union of any two (distinct) parallel lines in the same picture, - 2. one ``point at infinity'' union a cross in the corresponding picture, - 3. two ``points at infinity'' union a square in the picture corresponding - to the omitted point at infinity. + + 0. {3 "points at infinity"} $\cup$ {any line}, + 1. the union of any two (distinct) parallel lines in the same picture, + 2. one "point at infinity" union a cross in the corresponding picture, + 3. two "points at infinity" union a square in the picture corresponding + to the omitted point at infinity. + More precisely, there are 132 such hexads (12 of type 0, 12 of type 1, 54 of type 2, and 54 of type 3). They form a Steiner system of type $(5,6,12)$. EXAMPLES:: + sage: from sage.games.hexad import * sage: M = Minimog(type="shuffle") sage: M.find_hexad([0,1,2,3,4]) @@ -485,15 +517,18 @@ def find_hexad(self, pts): sage: M.find_hexad([1,2,3,4,SR(infinity)]) # random (machine dependent?) order ([+Infinity, 2, 3, 4, 1, 10], ['square 8', 'picture 0']) - AUTHOR:: - David Joyner (2006-05) + AUTHOR: - REFERENCES:: - R. Curtis, ``The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, - and the kitten,'' in {\bf Computational group theory}, ed. M. Atkinson, - Academic Press, 1984. - J. Conway, ``Hexacode and tetracode - MINIMOG and MOG,'' in {\bf Computational - group theory}, ed. M. Atkinson, Academic Press, 1984. + David Joyner (2006-05) + + REFERENCES: + + R. Curtis, The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, + and the kitten, in *Computational group theory*, ed. M. Atkinson, + Academic Press, 1984. + + J. Conway, Hexacode and tetracode - MINIMOG and MOG, in *Computational + group theory*, ed. M. Atkinson, Academic Press, 1984. """ MINIMOG = self.minimog @@ -574,7 +609,8 @@ def blackjack_move(self, L0): """ L is a list of cards of length 6, taken from {0,1,...,11}. - Mathematical blackjack:: + MATHEMATICAL BLACKJACK + Mathematical blackjack is played with 12 cards, labeled $0,...,11$ (for example: king, ace, $2$, $3$, ..., $10$, jack, where the king is $0$ and the jack is $11$). Divide the 12 cards into two piles of $6$ (to be @@ -582,8 +618,8 @@ def blackjack_move(self, L0): piles are to be placed face up on the table. The remaining cards are in a stack which is shared and visible to both players. If the sum of the cards face up on the table is less than 21 then no legal move is possible so you must - shuffle the cards and deal a new game. (Conway calls such a game *={0|0}, - where 0={|}; in this game the first player automatically wins.) + shuffle the cards and deal a new game. (Conway calls such a game `*={0|0}`, + where `0={|}`; in this game the first player automatically wins.) * Players alternate moves. * A move consists of exchanging a card on the table with a lower card from the other pile. @@ -599,6 +635,7 @@ def blackjack_move(self, L0): EXAMPLES:: + sage: M = Minimog(type="modulo11") sage: M.blackjack_move([0,2,3,6,1,10]) '6 --> 5. The total went from 22 to 21.' From 80590b7ad78199d16256bb78307379dcf0477763 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:34:01 +0200 Subject: [PATCH 529/665] sandpiles.sandpiles: rst fixes --- src/sage/sandpiles/sandpile.py | 98 +++++++++++++++++----------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 23d237a317d..1016181bb7f 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -1,61 +1,34 @@ -from string import join -import os -from sage.symbolic.all import I, pi -from sage.functions.log import exp -from sage.graphs.all import DiGraph, Graph, graphs, digraphs -from copy import deepcopy -from sage.rings.all import PolynomialRing, QQ, ZZ, lcm -from sage.misc.all import prod, det, forall, tmp_filename, random, randint, exists, denominator, srange -from sage.modules.free_module_element import vector -from sage.matrix.constructor import matrix, identity_matrix -from sage.interfaces.singular import singular -from sage.combinat.combinat import CombinatorialClass -from sage.combinat.set_partition import SetPartitions -from sage.homology.simplicial_complex import SimplicialComplex -from sage.plot.colors import rainbow -from sage.env import SAGE_LOCAL - r""" -To calculate linear systems associated with divisors, 4ti2 must be installed. -One way to do this is to run sage -i to install glpk, then 4ti2. See -http://sagemath.org/download-packages.html to get the exact names of these -packages. An alternative is to install 4ti2 separately, then point the -following variable to the correct path. -""" - -path_to_zsolve = os.path.join(SAGE_LOCAL,'bin','zsolve') - -r""" -Sage Sandpiles +Sandpiles Functions and classes for mathematical sandpiles. Version: 2.3 AUTHOR: - -- Marshall Hampton (2010-1-10) modified for inclusion as a module - within Sage library. - -- David Perkinson (2010-12-14) added show3d(), fixed bug in resolution(), - replaced elementary_divisors() with invariant_factors(), added show() for - SandpileConfig and SandpileDivisor. +- Marshall Hampton (2010-1-10) modified for inclusion as a module within Sage + library. + +- David Perkinson (2010-12-14) added show3d(), fixed bug in resolution(), + replaced elementary_divisors() with invariant_factors(), added show() for + SandpileConfig and SandpileDivisor. - -- David Perkinson (2010-9-18): removed is_undirected, added show(), added - verbose arguments to several functions to display SandpileConfigs and divisors as - lists of integers +- David Perkinson (2010-9-18): removed is_undirected, added show(), added + verbose arguments to several functions to display SandpileConfigs and + divisors as lists of integers - -- David Perkinson (2010-12-19): created separate SandpileConfig, SandpileDivisor, and - Sandpile classes +- David Perkinson (2010-12-19): created separate SandpileConfig, + SandpileDivisor, and Sandpile classes - -- David Perkinson (2009-07-15): switched to using config_to_list instead - of .values(), thus fixing a few bugs when not using integer labels for - vertices. +- David Perkinson (2009-07-15): switched to using config_to_list instead of + .values(), thus fixing a few bugs when not using integer labels for vertices. - -- David Perkinson (2009): many undocumented improvements +- David Perkinson (2009): many undocumented improvements - -- David Perkinson (2008-12-27): initial version +- David Perkinson (2008-12-27): initial version -EXAMPLES:: +EXAMPLES: A weighted directed graph given as a Python dictionary:: @@ -229,6 +202,33 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from string import join +import os +from sage.symbolic.all import I, pi +from sage.functions.log import exp +from sage.graphs.all import DiGraph, Graph, graphs, digraphs +from copy import deepcopy +from sage.rings.all import PolynomialRing, QQ, ZZ, lcm +from sage.misc.all import prod, det, forall, tmp_filename, random, randint, exists, denominator, srange +from sage.modules.free_module_element import vector +from sage.matrix.constructor import matrix, identity_matrix +from sage.interfaces.singular import singular +from sage.combinat.combinat import CombinatorialClass +from sage.combinat.set_partition import SetPartitions +from sage.homology.simplicial_complex import SimplicialComplex +from sage.plot.colors import rainbow +from sage.env import SAGE_LOCAL + +r""" +To calculate linear systems associated with divisors, 4ti2 must be installed. +One way to do this is to run sage -i to install glpk, then 4ti2. See +http://sagemath.org/download-packages.html to get the exact names of these +packages. An alternative is to install 4ti2 separately, then point the +following variable to the correct path. +""" + +path_to_zsolve = os.path.join(SAGE_LOCAL,'bin','zsolve') + class Sandpile(DiGraph): """ Class for Dhar's abelian sandpile model. @@ -586,7 +586,7 @@ def laplacian(self): [ 0 -1 0 -1 2 0] [ 0 0 -1 -1 0 2] - NOTES:: + NOTES: The function ``laplacian_matrix`` should be avoided. It returns the indegree version of the laplacian. @@ -1338,7 +1338,7 @@ def max_superstables(self, verbose=True): list (of maximal superstables) - EXAMPLES: + EXAMPLES:: sage: S=sandlib('riemann-roch2') sage: S.max_superstables() @@ -4725,9 +4725,11 @@ def grid_sandpile(m,n): The mxn grid sandpile. Each nonsink vertex has degree 4. INPUT: + ``m``, ``n`` - positive integers OUTPUT: + Sandpile with sink named ``sink``. EXAMPLES:: @@ -5308,8 +5310,8 @@ def firing_vector(S,D,E): INPUT: - - ``S`` -Sandpile - ``D``, ``E`` - tuples (representing linearly equivalent divisors) + - ``S`` - Sandpile + - ``D``, ``E`` - tuples (representing linearly equivalent divisors) OUTPUT: From d862438ca9ebb827956b73d03a1be391a899df84 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:06:06 +0200 Subject: [PATCH 530/665] matroids_plot_helpers: rst fixes --- src/sage/matroids/matroids_plot_helpers.py | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sage/matroids/matroids_plot_helpers.py b/src/sage/matroids/matroids_plot_helpers.py index ee95bab8304..05427294cc3 100644 --- a/src/sage/matroids/matroids_plot_helpers.py +++ b/src/sage/matroids/matroids_plot_helpers.py @@ -6,7 +6,7 @@ - Jayant Apte (2014-06-06): initial version - .. NOTE:: +.. NOTE:: This file provides functions that are called by ``show()`` and ``plot()`` methods of abstract matroids class. The basic idea is to first decide @@ -28,22 +28,24 @@ matroid. Loops and parallel elements are added as per conventions in [Oxley] using function ``addlp``. The priority order for point placement methods used inside plot() and show() is as follows: - 1) User Specified points dictionary and lineorders - 2) cached point placement dictionary and line orders (a list of ordered - lists) in M._cached_info (a dictionary) - 3) Internal point placement and orders deciding heuristics - If a custom point placement and/or line orders is desired, then user can - simply specify the custom points dictionary as ``M.cached info = - {'plot_positions':, - 'plot_lineorders':}`` + + 1. User Specified points dictionary and lineorders + 2. cached point placement dictionary and line orders (a list of ordered + lists) in M._cached_info (a dictionary) + 3. Internal point placement and orders deciding heuristics + If a custom point placement and/or line orders is desired, then user + can simply specify the custom points dictionary as:: + + M.cached info = {'plot_positions':, + 'plot_lineorders':} REFERENCES ========== -.. [Oxley] James Oxley, "Matroid Theory, Second Edition". Oxford University - Press, 2011. +[Oxley] James Oxley, "Matroid Theory, Second Edition". Oxford University +Press, 2011. EXAMPLES:: @@ -744,16 +746,16 @@ def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False): - ``M1`` -- A matroid. - ``B1`` -- (optional) A list of elements in ``M1.groundset()`` that - correspond to a basis of ``M1`` and will be placed as vertices of the - triangle in the geometric representation of ``M1``. + correspond to a basis of ``M1`` and will be placed as vertices of the + triangle in the geometric representation of ``M1``. - ``lineorders1`` -- (optional) A list of ordered lists of elements of - ``M1.grondset()`` such that if a line in geometric representation is - setwise same as any of these then points contained will be traversed in - that order thus overriding internal order deciding heuristic. + ``M1.grondset()`` such that if a line in geometric representation is + setwise same as any of these then points contained will be traversed in + that order thus overriding internal order deciding heuristic. - ``pd`` - (optional) A dictionary mapping ground set elements to their - (x,y) positions. + (x,y) positions. - ``sp`` -- (optional) If True, a positioning dictionary and line orders - will be placed in ``M._cached_info``. + will be placed in ``M._cached_info``. OUTPUT: From 776d9bd309eb95ac6c4aae6904ae73662f204212 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:06:27 +0200 Subject: [PATCH 531/665] modform.theta: rst fixes --- src/sage/modular/modform/theta.py | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/sage/modular/modform/theta.py b/src/sage/modular/modform/theta.py index 22d47bf3172..5728a0afaf3 100644 --- a/src/sage/modular/modform/theta.py +++ b/src/sage/modular/modform/theta.py @@ -2,7 +2,8 @@ q-expansions of Theta Series AUTHOR: - -- William Stein + +William Stein """ from sage.rings.all import Integer, ZZ, PowerSeriesRing @@ -11,20 +12,21 @@ def theta2_qexp(prec=10, var='q', K=ZZ, sparse=False): r""" - Return the $q$-expansion of the series - $$ - \theta_2 = \sum_{n odd} q^{n^2}. - $$ + Return the `q`-expansion of the series + ` \theta_2 = \sum_{n odd} q^{n^2}. ` INPUT: - prec -- integer; the absolute precision of the output - var -- (default: 'q') variable name - K -- (default: ZZ) base ring of answer + + - prec -- integer; the absolute precision of the output + - var -- (default: 'q') variable name + - K -- (default: ZZ) base ring of answer OUTPUT: - a power series over K - EXAMPLES: + a power series over K + + EXAMPLES:: + sage: theta2_qexp(18) q + q^9 + O(q^18) sage: theta2_qexp(49) @@ -60,20 +62,21 @@ def theta2_qexp(prec=10, var='q', K=ZZ, sparse=False): def theta_qexp(prec=10, var='q', K=ZZ, sparse=False): r""" - Return the $q$-expansion of the standard $\theta$ series - $$ - \theta = 1 + 2\sum_{n=1}{^\infty} q^{n^2}. - $$ + Return the `q`-expansion of the standard `\theta` series + ` \theta = 1 + 2\sum_{n=1}{^\infty} q^{n^2}. ` INPUT: - prec -- integer; the absolute precision of the output - var -- (default: 'q') variable name - K -- (default: ZZ) base ring of answer + + - prec -- integer; the absolute precision of the output + - var -- (default: 'q') variable name + - K -- (default: ZZ) base ring of answer OUTPUT: - a power series over K - EXAMPLES: + a power series over K + + EXAMPLES:: + sage: theta_qexp(25) 1 + 2*q + 2*q^4 + 2*q^9 + 2*q^16 + O(q^25) sage: theta_qexp(10) From ba3aa088154e32519ef9ba2e066eaff5f2228e37 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:07:05 +0200 Subject: [PATCH 532/665] cunningham_tables: rst fixes --- src/sage/databases/cunningham_tables.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/databases/cunningham_tables.py b/src/sage/databases/cunningham_tables.py index 6196b1eacae..32ff38b3e60 100644 --- a/src/sage/databases/cunningham_tables.py +++ b/src/sage/databases/cunningham_tables.py @@ -1,3 +1,7 @@ +r""" +Cunningham table +""" + import os from sage.misc.cachefunc import cached_function from sage.rings.integer import Integer From 7dbf5697f60d8233ace6d90a11f82deb04c48e10 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:07:19 +0200 Subject: [PATCH 533/665] monoids.strings_ops: rst fixes --- src/sage/monoids/string_ops.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/monoids/string_ops.py b/src/sage/monoids/string_ops.py index cab8e9b10ce..9a2caa5dd7b 100644 --- a/src/sage/monoids/string_ops.py +++ b/src/sage/monoids/string_ops.py @@ -1,3 +1,5 @@ +"Utility functions on strings" + #***************************************************************************** # Copyright (C) 2007 David Kohel # @@ -12,7 +14,9 @@ def strip_encoding(S): """ The upper case string of S stripped of all non-alphabetic characters. - EXAMPLES: + + EXAMPLES:: + sage: S = "The cat in the hat." sage: strip_encoding(S) 'THECATINTHEHAT' @@ -53,7 +57,9 @@ def frequency_distribution(S, n=1, field=None): def coincidence_index(S,n=1): """ The coincidence index of the string S. - EXAMPLES: + + EXAMPLES:: + sage: S = strip_encoding("The cat in the hat.") sage: coincidence_index(S) 0.120879120879121 @@ -82,7 +88,8 @@ def coincidence_discriminant(S,n=2): Output: A measure of the difference of probability of association of character pairs, relative to their independent one-character probabilities. - EXAMPLES: + EXAMPLES:: + sage: S = strip_encoding("The cat in the hat.") sage: coincidence_discriminant([ S[i:i+2] for i in range(len(S)-1) ]) 0.0827001855677322 From 4e7150b9873426b9f594d0d242b8d0e9d9bc3501 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:07:49 +0200 Subject: [PATCH 534/665] stats.r: rst fixes --- src/sage/stats/r.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/stats/r.py b/src/sage/stats/r.py index a047717a146..4e662e74e5e 100644 --- a/src/sage/stats/r.py +++ b/src/sage/stats/r.py @@ -1,3 +1,5 @@ +"T-test using R" + ########################################################################## # # Copyright (C) 2007 William Stein @@ -20,13 +22,16 @@ def ttest(x,y,conf_level = 0.95, **kw): T-Test using R Arguments: - x, y -- vectors of same length - conf_level -- confidence level of the interval, [0,1) in percent + + - x, y -- vectors of same length + - conf_level -- confidence level of the interval, [0,1) in percent Result: + Tuple: (p-value, R return object) - Example: + Example:: + sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a 0.941026372027427 """ From 905af7136a364e64796794ec1ad6e85f325aef2b Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:09:40 +0200 Subject: [PATCH 535/665] Ref: remove duplicate entry in r/algebras --- src/doc/en/reference/algebras/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 4e5792d031b..26fb2e78a01 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -27,7 +27,6 @@ Algebras sage/algebras/group_algebra - sage/algebras/iwahori_hecke_algebra sage/algebras/iwahori_hecke_algebra sage/algebras/nil_coxeter_algebra sage/algebras/affine_nil_temperley_lieb From 066a1143cd071ff6bde9401530e4533b343c5a8f Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 15:10:25 +0200 Subject: [PATCH 536/665] Ref: add missing modules to various parts of the manual --- src/doc/en/reference/arithgroup/index.rst | 2 +- src/doc/en/reference/categories/index.rst | 1 + src/doc/en/reference/cryptography/index.rst | 1 + src/doc/en/reference/databases/index.rst | 3 +++ src/doc/en/reference/dynamics/index.rst | 3 ++- src/doc/en/reference/finance/index.rst | 1 + src/doc/en/reference/finite_rings/index.rst | 4 ++++ src/doc/en/reference/games/index.rst | 9 +++++++++ src/doc/en/reference/groups/index.rst | 17 ++++++++++++++++- src/doc/en/reference/libs/index.rst | 1 + src/doc/en/reference/matroids/index.rst | 11 +++++++++++ src/doc/en/reference/modfrm/index.rst | 4 +++- src/doc/en/reference/modsym/index.rst | 3 +++ src/doc/en/reference/monoids/index.rst | 2 ++ src/doc/en/reference/numerical/index.rst | 5 +++++ src/doc/en/reference/padics/index.rst | 4 ++++ src/doc/en/reference/parallel/index.rst | 4 ++++ src/doc/en/reference/quivers/index.rst | 1 + src/doc/en/reference/sat/index.rst | 4 ++++ src/doc/en/reference/stats/index.rst | 2 ++ .../en/reference/tensor_free_modules/index.rst | 2 ++ 21 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/doc/en/reference/arithgroup/index.rst b/src/doc/en/reference/arithgroup/index.rst index bd655f9a41d..26a1dcf403f 100644 --- a/src/doc/en/reference/arithgroup/index.rst +++ b/src/doc/en/reference/arithgroup/index.rst @@ -17,6 +17,6 @@ the modular group `{\rm SL}_2(\ZZ)`. sage/modular/arithgroup/congroup_gamma sage/modular/arithgroup/congroup_sl2z sage/modular/arithgroup/farey_symbol - sage/modular/arithgroup/congroup_pyx + sage/modular/arithgroup/congroup .. include:: ../footer.txt diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index a4f41af65e6..c8943d8312f 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -198,6 +198,7 @@ Miscellaneous :maxdepth: 2 sage/categories/action + sage/categories/category_cy_helper sage/categories/poor_man_map .. include:: ../footer.txt diff --git a/src/doc/en/reference/cryptography/index.rst b/src/doc/en/reference/cryptography/index.rst index c0b50f5b098..5c0aac5239c 100644 --- a/src/doc/en/reference/cryptography/index.rst +++ b/src/doc/en/reference/cryptography/index.rst @@ -23,6 +23,7 @@ Cryptography sage/crypto/util sage/crypto/boolean_function + sage/crypto/mq/mpolynomialsystemgenerator sage/crypto/mq/sr sage/crypto/mq/sbox diff --git a/src/doc/en/reference/databases/index.rst b/src/doc/en/reference/databases/index.rst index 069c362f0be..6c24222bda7 100644 --- a/src/doc/en/reference/databases/index.rst +++ b/src/doc/en/reference/databases/index.rst @@ -58,5 +58,8 @@ database engine. sage/databases/conway sage/databases/odlyzko sage/databases/symbolic_data + sage/databases/cunningham_tables + sage/databases/db_class_polynomials + sage/databases/db_modular_polynomials .. include:: ../footer.txt diff --git a/src/doc/en/reference/dynamics/index.rst b/src/doc/en/reference/dynamics/index.rst index 7bc1004aed2..17779fe74ef 100644 --- a/src/doc/en/reference/dynamics/index.rst +++ b/src/doc/en/reference/dynamics/index.rst @@ -8,9 +8,10 @@ Discrete dynamics interval_exchanges flat_surfaces + sage/sandpiles/sandpile .. SEEALSO:: - - :ref:`sage.combinat.e_one_star` + - :mod:`sage.combinat.e_one_star` .. include:: ../footer.txt diff --git a/src/doc/en/reference/finance/index.rst b/src/doc/en/reference/finance/index.rst index f889939862f..28bddb84cd8 100644 --- a/src/doc/en/reference/finance/index.rst +++ b/src/doc/en/reference/finance/index.rst @@ -9,6 +9,7 @@ Quantitative Finance sage/finance/option sage/finance/fractal sage/finance/markov_multifractal + sage/finance/markov_multifractal_cython .. include:: ../footer.txt diff --git a/src/doc/en/reference/finite_rings/index.rst b/src/doc/en/reference/finite_rings/index.rst index fdf98a01592..210735c11c8 100644 --- a/src/doc/en/reference/finite_rings/index.rst +++ b/src/doc/en/reference/finite_rings/index.rst @@ -14,7 +14,11 @@ Finite Rings sage/rings/finite_rings/finite_field_ntl_gf2e sage/rings/finite_rings/finite_field_pari_ffelt sage/rings/finite_rings/finite_field_prime_modn + sage/rings/finite_rings/hom_finite_field sage/rings/finite_rings/homset + sage/rings/finite_rings/hom_finite_field + sage/rings/finite_rings/hom_finite_field_givaro + sage/rings/finite_rings/hom_prime_finite_field sage/rings/finite_rings/integer_mod_ring sage/rings/finite_rings/residue_field sage/rings/algebraic_closure_finite_field diff --git a/src/doc/en/reference/games/index.rst b/src/doc/en/reference/games/index.rst index 9123f415031..8511337bb5d 100644 --- a/src/doc/en/reference/games/index.rst +++ b/src/doc/en/reference/games/index.rst @@ -10,5 +10,14 @@ Rubik's cube solver (see sage/games/sudoku sage/games/quantumino + sage/games/hexad + +Internals +--------- + +.. toctree:: + :maxdepth: 1 + + sage/games/sudoku_backtrack .. include:: ../footer.txt diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index b0974cdc9bf..3ef8d105455 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -6,7 +6,11 @@ Groups sage/groups/groups_catalog sage/groups/group + sage/groups/group_homset sage/groups/libgap_wrapper + sage/groups/libgap_group + sage/groups/libgap_mixin + sage/groups/pari_group sage/groups/generic sage/groups/free_group sage/groups/finitely_presented @@ -47,7 +51,18 @@ Groups sage/groups/misc_gps/misc_groups sage/groups/semimonomial_transformations/semimonomial_transformation_group sage/groups/semimonomial_transformations/semimonomial_transformation - + sage/groups/class_function sage/groups/conjugacy_classes + sage/groups/perm_gps/partn_ref + sage/groups/perm_gps/partn_ref2 + + +Internals +--------- + +.. toctree:: + :maxdepth: 2 + + sage/groups/matrix_gps/named_group .. include:: ../footer.txt diff --git a/src/doc/en/reference/libs/index.rst b/src/doc/en/reference/libs/index.rst index b0faf6b0203..3c09c38f3ea 100644 --- a/src/doc/en/reference/libs/index.rst +++ b/src/doc/en/reference/libs/index.rst @@ -51,6 +51,7 @@ to be aware of the modules described in this chapter. sage/libs/pari/gen_py sage/libs/pari/gen sage/libs/pari/pari_instance + sage/rings/pari_ring sage/libs/fplll/fplll sage/libs/readline sage/libs/gap/context_managers diff --git a/src/doc/en/reference/matroids/index.rst b/src/doc/en/reference/matroids/index.rst index f3abc562868..208bdfc0075 100644 --- a/src/doc/en/reference/matroids/index.rst +++ b/src/doc/en/reference/matroids/index.rst @@ -50,4 +50,15 @@ Advanced functionality sage/matroids/utilities sage/matroids/extension +Internals +--------- + +.. toctree:: + :maxdepth: 1 + + sage/matroids/lean_matrix + sage/matroids/matroids_plot_helpers + sage/matroids/set_system + sage/matroids/unpickling + .. include:: ../footer.txt diff --git a/src/doc/en/reference/modfrm/index.rst b/src/doc/en/reference/modfrm/index.rst index 97934862f88..bcede5f77b8 100644 --- a/src/doc/en/reference/modfrm/index.rst +++ b/src/doc/en/reference/modfrm/index.rst @@ -23,6 +23,8 @@ Modular Forms sage/modular/modform/ambient sage/modular/modform/half_integral sage/modular/modform/find_generators - + sage/modular/modform/j_invariant + sage/modular/modform/notes + sage/modular/modform/theta .. include:: ../footer.txt diff --git a/src/doc/en/reference/modsym/index.rst b/src/doc/en/reference/modsym/index.rst index 5cafcdf0f21..5111f74408a 100644 --- a/src/doc/en/reference/modsym/index.rst +++ b/src/doc/en/reference/modsym/index.rst @@ -27,5 +27,8 @@ Modular Symbols sage/modular/modsym/p1list_nf + sage/modular/modsym/apply + sage/modular/modsym/hecke_operator + sage/modular/modsym/relation_matrix_pyx .. include:: ../footer.txt diff --git a/src/doc/en/reference/monoids/index.rst b/src/doc/en/reference/monoids/index.rst index f41d8f09841..bee105a3848 100644 --- a/src/doc/en/reference/monoids/index.rst +++ b/src/doc/en/reference/monoids/index.rst @@ -17,4 +17,6 @@ finite number of indeterminates. sage/monoids/string_monoid_element sage/monoids/string_monoid + sage/monoids/string_ops + .. include:: ../footer.txt diff --git a/src/doc/en/reference/numerical/index.rst b/src/doc/en/reference/numerical/index.rst index 4893fc2531b..7ab7cc8e18f 100644 --- a/src/doc/en/reference/numerical/index.rst +++ b/src/doc/en/reference/numerical/index.rst @@ -25,6 +25,11 @@ LP Solver backends sage/numerical/backends/ppl_backend sage/numerical/backends/cvxopt_backend +.. backends depending on optional packages +.. sage/numerical/backends/coin_backend +.. sage/numerical/backends/cplex_backend +.. sage/numerical/backends/gurobi_backend + Sage also supports, via optional packages, CBC (COIN-OR), CPLEX (ILOG), and Gurobi. In order to find out how to use them in Sage, please refer to the `Thematic Tutorial on Linear Programming diff --git a/src/doc/en/reference/padics/index.rst b/src/doc/en/reference/padics/index.rst index cb0d45b1a7c..84c04b77952 100644 --- a/src/doc/en/reference/padics/index.rst +++ b/src/doc/en/reference/padics/index.rst @@ -43,4 +43,8 @@ p-Adics sage/rings/padics/precision_error sage/rings/padics/misc + sage/rings/padics/common_conversion + sage/rings/padics/discrete_value_group + sage/rings/padics/morphism + .. include:: ../footer.txt diff --git a/src/doc/en/reference/parallel/index.rst b/src/doc/en/reference/parallel/index.rst index 0da2bc69644..a24820055aa 100644 --- a/src/doc/en/reference/parallel/index.rst +++ b/src/doc/en/reference/parallel/index.rst @@ -10,4 +10,8 @@ Parallel Computing sage/parallel/multiprocessing_sage sage/parallel/ncpus +.. SEEALSO:: + + - :ref:`sage.interfaces.psage` + .. include:: ../footer.txt diff --git a/src/doc/en/reference/quivers/index.rst b/src/doc/en/reference/quivers/index.rst index d377b996833..b29c84f807e 100644 --- a/src/doc/en/reference/quivers/index.rst +++ b/src/doc/en/reference/quivers/index.rst @@ -8,6 +8,7 @@ Quivers sage/quivers/homspace sage/quivers/morphism sage/quivers/path_semigroup + sage/quivers/paths sage/quivers/representation .. include:: ../footer.txt diff --git a/src/doc/en/reference/sat/index.rst b/src/doc/en/reference/sat/index.rst index 647c8c0c183..37adb48dd03 100644 --- a/src/doc/en/reference/sat/index.rst +++ b/src/doc/en/reference/sat/index.rst @@ -91,7 +91,11 @@ Details on Specific Solvers .. toctree:: :maxdepth: 1 + sage/sat/solvers/satsolver sage/sat/solvers/dimacs +.. optional - cryptominisat +.. sage/sat/solvers/cryptominisat/cryptominisat +.. sage/sat/solvers/cryptominisat/solverconf Converters ---------- diff --git a/src/doc/en/reference/stats/index.rst b/src/doc/en/reference/stats/index.rst index e67f10f6891..e55454305c6 100644 --- a/src/doc/en/reference/stats/index.rst +++ b/src/doc/en/reference/stats/index.rst @@ -15,4 +15,6 @@ Statistics sage/stats/distributions/discrete_gaussian_polynomial sage/stats/distributions/discrete_gaussian_lattice + sage/stats/r + .. include:: ../footer.txt diff --git a/src/doc/en/reference/tensor_free_modules/index.rst b/src/doc/en/reference/tensor_free_modules/index.rst index c8f0b58b988..89f81db9f25 100644 --- a/src/doc/en/reference/tensor_free_modules/index.rst +++ b/src/doc/en/reference/tensor_free_modules/index.rst @@ -23,4 +23,6 @@ a self-consistent subset that can be used independently of SageManifolds. sage/tensor/modules/comp + sage/tensor/modules/format_utilities + .. include:: ../footer.txt From 8e47f6ad274a378244da7d0f7dffc08b4b6ae6bb Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 25 Apr 2015 09:12:11 +0200 Subject: [PATCH 537/665] #18170 make pdf docs build + cosmetic fixes --- src/doc/en/reference/finite_rings/index.rst | 3 +- src/doc/en/reference/modfrm/index.rst | 12 +++++++- src/sage/databases/db_modular_polynomials.py | 2 +- src/sage/games/hexad.py | 30 ++++++++++---------- src/sage/misc/latex.py | 6 ++-- src/sage/sandpiles/sandpile.py | 15 +++++----- src/sage/sat/solvers/satsolver.pyx | 2 +- 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/doc/en/reference/finite_rings/index.rst b/src/doc/en/reference/finite_rings/index.rst index 210735c11c8..8f8519b7583 100644 --- a/src/doc/en/reference/finite_rings/index.rst +++ b/src/doc/en/reference/finite_rings/index.rst @@ -15,10 +15,9 @@ Finite Rings sage/rings/finite_rings/finite_field_pari_ffelt sage/rings/finite_rings/finite_field_prime_modn sage/rings/finite_rings/hom_finite_field - sage/rings/finite_rings/homset - sage/rings/finite_rings/hom_finite_field sage/rings/finite_rings/hom_finite_field_givaro sage/rings/finite_rings/hom_prime_finite_field + sage/rings/finite_rings/homset sage/rings/finite_rings/integer_mod_ring sage/rings/finite_rings/residue_field sage/rings/algebraic_closure_finite_field diff --git a/src/doc/en/reference/modfrm/index.rst b/src/doc/en/reference/modfrm/index.rst index bcede5f77b8..e1f8a483a3f 100644 --- a/src/doc/en/reference/modfrm/index.rst +++ b/src/doc/en/reference/modfrm/index.rst @@ -1,6 +1,9 @@ Modular Forms ============= +Module List +----------- + .. toctree:: :maxdepth: 2 @@ -24,7 +27,14 @@ Modular Forms sage/modular/modform/half_integral sage/modular/modform/find_generators sage/modular/modform/j_invariant - sage/modular/modform/notes sage/modular/modform/theta +Design Notes +------------ + +.. toctree:: + :maxdepth: 2 + + sage/modular/modform/notes + .. include:: ../footer.txt diff --git a/src/sage/databases/db_modular_polynomials.py b/src/sage/databases/db_modular_polynomials.py index 9b5fb2e80f3..017cbc9a89d 100644 --- a/src/sage/databases/db_modular_polynomials.py +++ b/src/sage/databases/db_modular_polynomials.py @@ -141,7 +141,7 @@ def __init__(self): class DedekindEtaModularCorrespondenceDatabase(ModularCorrespondenceDatabase): """ The database of modular correspondences in $X_0(p) \times X_0(p)$, where - the model of the curves $X_0(p) = \PP^1$ are specified by quotients of + the model of the curves $X_0(p) = \Bold{P}^1$ are specified by quotients of Dedekind's eta function. """ def __init__(self): diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index 980a491cfe2..d0ae2b29652 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -50,7 +50,7 @@ REFERENCES: -R. Curtis, The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, +R. Curtis, The Steiner system `S(5,6,12)`, the Mathieu group `M_{12}`, and the kitten, in *Computational group theory*, ed. M. Atkinson, Academic Press, 1984. @@ -405,7 +405,7 @@ def find_hexad2(self, pts, x0): OUTPUT: - hexad containing `S \union \{x0\}` of type 2 + hexad containing `S \cup \{x0\}` of type 2 EXAMPLES:: @@ -440,7 +440,7 @@ def find_hexad2(self, pts, x0): return [],[] def find_hexad3(self, pts, x0, x1): - """ + r""" INPUT: - pts -- a list of 3 elements of MINIMOG, not including any "points at @@ -449,7 +449,7 @@ def find_hexad3(self, pts, x0, x1): OUTPUT: - hexad containing pts \union \{x0,x1\} of type 3 (square at + hexad containing pts union \{x0,x1\} of type 3 (square at picture of "omitted point at infinity") EXAMPLES:: @@ -479,27 +479,27 @@ def find_hexad3(self, pts, x0, x1): return [],[] def find_hexad(self, pts): - """ + r""" INPUT: pts -- a list S of 5 elements of MINIMOG OUTPUT: - hexad containing $S \union \{x0\}$ of some type + hexad containing `S \cup \{x0\}` of some type NOTE: 3 "points at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]} Theorem (Curtis, Conway): Each hexads is of exactly one of the following types: - 0. {3 "points at infinity"} $\cup$ {any line}, + 0. {3 "points at infinity"} union {any line}, 1. the union of any two (distinct) parallel lines in the same picture, 2. one "point at infinity" union a cross in the corresponding picture, 3. two "points at infinity" union a square in the picture corresponding to the omitted point at infinity. More precisely, there are 132 such hexads (12 of type 0, 12 of type 1, 54 of type 2, - and 54 of type 3). They form a Steiner system of type $(5,6,12)$. + and 54 of type 3). They form a Steiner system of type `(5,6,12)`. EXAMPLES:: @@ -523,7 +523,7 @@ def find_hexad(self, pts): REFERENCES: - R. Curtis, The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$, + R. Curtis, The Steiner system `S(5,6,12)`, the Mathieu group `M_{12}`, and the kitten, in *Computational group theory*, ed. M. Atkinson, Academic Press, 1984. @@ -611,10 +611,10 @@ def blackjack_move(self, L0): MATHEMATICAL BLACKJACK - Mathematical blackjack is played with 12 cards, labeled $0,...,11$ - (for example: king, ace, $2$, $3$, ..., $10$, jack, where the king is - $0$ and the jack is $11$). Divide the 12 cards into two piles of $6$ (to be - fair, this should be done randomly). Each of the $6$ cards of one of these + Mathematical blackjack is played with 12 cards, labeled `0,...,11` + (for example: king, ace, `2`, `3`, ..., `10`, jack, where the king is + `0` and the jack is `11`). Divide the 12 cards into two piles of `6` (to be + fair, this should be done randomly). Each of the `6` cards of one of these piles are to be placed face up on the table. The remaining cards are in a stack which is shared and visible to both players. If the sum of the cards face up on the table is less than 21 then no legal move is possible so you must @@ -626,9 +626,9 @@ def blackjack_move(self, L0): * The player whose move makes the sum of the cards on the table under 21 loses. The winning strategy (given below) for this game is due to Conway and Ryba. - There is a Steiner system $S(5,6,12)$ of hexads in the set $\{0,1,...,11\}$. + There is a Steiner system `S(5,6,12)` of hexads in the set `\{0,1,...,11\}`. This Steiner system is associated to the MINIMOG of in the "shuffle numbering" - rather than the "modulo $11$ labeling". + rather than the "modulo `11` labeling". Proposition (Ryba, Conway) For this Steiner system, the winning strategy is to choose a move which is a hexad from this system. diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 9648672755c..ef76d09d4e4 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -5,10 +5,10 @@ special method ``_latex_(self)`` that returns a string, which will be typeset in a mathematical mode (the exact mode depends on circumstances). - AUTHORS: +AUTHORS: - - William Stein: original implementation - - Joel B. Mohler: latex_variable_name() drastic rewrite and many doc-tests +- William Stein: original implementation +- Joel B. Mohler: latex_variable_name() drastic rewrite and many doc-tests """ #***************************************************************************** diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 1016181bb7f..69b58900711 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -194,7 +194,14 @@ sage: p.axes_labels(['log(N)','log(D(N))']) sage: t = text("Distribution of avalanche sizes", (2,2), rgbcolor=(1,0,0)) sage: show(p+t,axes_labels=['log(N)','log(D(N))']) + +To calculate linear systems associated with divisors, 4ti2 must be installed. +One way to do this is to run sage -i to install glpk, then 4ti2. See +http://sagemath.org/download-packages.html to get the exact names of these +packages. An alternative is to install 4ti2 separately, then point the +following variable to the correct path. """ + #***************************************************************************** # Copyright (C) 2011 David Perkinson # @@ -219,14 +226,6 @@ from sage.plot.colors import rainbow from sage.env import SAGE_LOCAL -r""" -To calculate linear systems associated with divisors, 4ti2 must be installed. -One way to do this is to run sage -i to install glpk, then 4ti2. See -http://sagemath.org/download-packages.html to get the exact names of these -packages. An alternative is to install 4ti2 separately, then point the -following variable to the correct path. -""" - path_to_zsolve = os.path.join(SAGE_LOCAL,'bin','zsolve') class Sandpile(DiGraph): diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 342105078aa..102ce003d78 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -1,5 +1,5 @@ """ -Abstract SAT Solver. +Abstract SAT Solver All SAT solvers must inherit from this class. From 8b0cf3903f70460883cd4b8ba4ba90b0c30f7d8f Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 25 Apr 2015 10:29:13 +0200 Subject: [PATCH 538/665] Fix doctest different on 32 vs. 64 bits --- src/sage/structure/coerce.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index bfe2ac2eb7f..98b36fd1055 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -332,7 +332,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: numpy.uint8('2') + 3 5 sage: type(_) - + # 32-bit + # 64-bit sage: numpy.int8('12') + 1/3 12.333333333333334 From faf83a1380dde69c2dfd7849c1b8b8d24dcbecd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sat, 25 Apr 2015 10:37:25 +0200 Subject: [PATCH 539/665] 16659: added missing hecke_monoid.py file --- src/sage/monoids/hecke_monoid.py | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/sage/monoids/hecke_monoid.py diff --git a/src/sage/monoids/hecke_monoid.py b/src/sage/monoids/hecke_monoid.py new file mode 100644 index 00000000000..8db027b6d35 --- /dev/null +++ b/src/sage/monoids/hecke_monoid.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +""" +Hecke Monoids +""" +#***************************************************************************** +# Copyright (C) 2015 Nicolas M. Thiéry +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#***************************************************************************** +from sage.misc.cachefunc import cached_function +from sage.sets.finite_set_maps import FiniteSetMaps + +@cached_function +def HeckeMonoid(W): + r""" + Return the `0`-Hecke monoid of the Coxeter group `W`. + + INPUT: + + - `W` -- a finite Coxeter group + + Let `s_1,\ldots,s_n` be the simple reflections of `W`. The 0-Hecke + monoid is the monoid generated by projections `\pi_1,\ldots,\pi_n` + satisfying the same braid and commutation relations as the `s_i`. + It is of same cardinality as `W`. + + .. NOTE:: + + This is currently a very basic implementation as the submonoid + of sorting maps on `W` generated by the simple projections of + `W`. It's only functional for `W` finite. + + .. SEEALSO:: + + - :class:`CoxeterGroups` + - :class:`CoxeterGroups.ParentMethods.simple_projections` + - :class:`IwahoriHeckeAlgebra` + + EXAMPLES:: + + sage: from sage.monoids.hecke_monoid import HeckeMonoid + sage: W = SymmetricGroup(4) + sage: H = HeckeMonoid(W); H + 0-Hecke monoid of the Symmetric group of order 4! as a permutation group + sage: pi = H.monoid_generators(); pi + Finite family {1: ..., 2: ..., 3: ...} + sage: all(pi[i]^2 == pi[i] for i in pi.keys()) + True + sage: pi[1] * pi[2] * pi[1] == pi[2] * pi[1] * pi[2] + True + sage: pi[2] * pi[3] * pi[2] == pi[3] * pi[2] * pi[3] + True + sage: pi[1] * pi[3] == pi[3] * pi[1] + True + sage: H.cardinality() + 24 + """ + ambient_monoid = FiniteSetMaps(W, action="right") + pi = W.simple_projections(length_increasing=True).map(ambient_monoid) + H = ambient_monoid.submonoid(pi) + H.rename("0-Hecke monoid of the %s"%W) + return H From cf23812d816c93fa926ec5652d627782334bc19d Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:31:47 +0200 Subject: [PATCH 540/665] polynomial_compiled: rst fixes --- .../rings/polynomial/polynomial_compiled.pyx | 84 +++++++++++-------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_compiled.pyx b/src/sage/rings/polynomial/polynomial_compiled.pyx index 62a810bc38f..decf99b6da0 100644 --- a/src/sage/rings/polynomial/polynomial_compiled.pyx +++ b/src/sage/rings/polynomial/polynomial_compiled.pyx @@ -2,8 +2,9 @@ Polynomial Compilers AUTHORS: - -- Tom Boothby, initial design & implementation - -- Robert Bradshaw, bug fixes / suggested & assisted with significant design improvements + +- Tom Boothby, initial design & implementation +- Robert Bradshaw, bug fixes / suggested & assisted with significant design improvements """ ################################################################################ @@ -19,15 +20,16 @@ from sage.misc.decorators import rename_keyword cdef class CompiledPolynomialFunction: """ - Builds a reasonably optimized directed acyclic graph representation + Builds a reasonably optimized directed acyclic graph representation for a given polynomial. A CompiledPolynomialFunction is callable from python, though it is a little faster to call the eval function from pyrex. - This class is not intended to be called by a user, rather, it is + This class is not intended to be called by a user, rather, it is intended to improve the performance of immutable polynomial objects. - TODO: + TODO:: + [ ] Recursive calling [ ] Faster casting of coefficients / argument [ ] Multivariate polynomials @@ -55,10 +57,12 @@ cdef class CompiledPolynomialFunction: Scan through coefficient list, and record the lengths of sequences of zero coefficients. This corresponds to collapsing Horner's Form into a reduced representation. - For example, + For example, :: + x^8 + x^4 + x^2 + 1 = ((((((((1)*x + 0)*x+0)*x+0)*x+1)*x+0)*x+0)*x+1)*x+0)*x+1 = ((((1)*x^4 + 1)*x^2 + 1)*x^2 + 1 + gives a list of "gaps": [2,4] Step 2: Fill in Gap Structure. @@ -67,7 +71,8 @@ cdef class CompiledPolynomialFunction: the computation of all desired exponents. Record this sequence of steps as an evaluation DAG, and retain references to the nodes representing the desired - exponents. For the example above, we would have: + exponents. For the example above, we would have:: + x^2 = x*x x^4 = (x^2) * (x^2) @@ -80,18 +85,18 @@ cdef class CompiledPolynomialFunction: Implementation considerations: - * By combining steps 1 and 3, we greatly improve the speed of - this construction, but some complexity is introduced. The - solution to this is that "dummy" nodes are created to represent - the desired gaps. As the structure of the gaps is filled in, - these dummies get references to usable DAG nodes. After all gaps - are filled in, we strip out dummy nodes, and are left with a - complete representation of our polynomial. + * By combining steps 1 and 3, we greatly improve the speed of + this construction, but some complexity is introduced. The + solution to this is that "dummy" nodes are created to represent + the desired gaps. As the structure of the gaps is filled in, + these dummies get references to usable DAG nodes. After all gaps + are filled in, we strip out dummy nodes, and are left with a + complete representation of our polynomial. - * The "binary" algorithm (currently the only algorithm; others are - forthcoming) requires the gaps to considered in order, and adds - additional dummies as it goes. Hence, the gaps are put into a - binary tree. + * The "binary" algorithm (currently the only algorithm; others are + forthcoming) requires the gaps to considered in order, and adds + additional dummies as it goes. Hence, the gaps are put into a + binary tree. """ cdef generic_pd max_gap, dag @@ -190,9 +195,12 @@ cdef class CompiledPolynomialFunction: squaring nodes, we give the current dummy node a usable dag of the appropriate type, which treats the nodes being operated on as argument. That is, if we want to multiply nodes A and B, and - give the result to M, we would call + give the result to M, we would call :: + M.fill(mul_pd(A,B)) - and refer to this operation as + + and refer to this operation as :: + M = A*B Sometimes we want a node that isn't in the tree. In that case, we @@ -203,21 +211,27 @@ cdef class CompiledPolynomialFunction: Fill in the gaps with the following algorithm: - Step 1: Remove max node from the tree, denote its width m. - If m == 1, halt. - Step 2: If m is even, check if m/2 is already in our tree. - If yes, square the node corresponding to m/2, and - go to step 1. - Step 3: Peek at the next-largest, and denote its width n. - Write m = qn+r. - If r != 0, get the node R, whose gap-width is r. - Also, get the node QN, whose width is qn. - Then, set M = R*QN and go to step 1. - If r == 0, we have two cases: - q is even: get/create the node for q/n, denote it T. - Set M = T**2 and go to step 1. - q is odd: get/create the node for (Q-1)*N, denote it T. - Set M = T*N and go to step 1. + | Step 1: + | Remove max node from the tree, denote its width m. + | If m == 1, halt. + | + | Step 2: + | If m is even, check if m/2 is already in our tree. + | If yes, square the node corresponding to m/2, and go to step 1. + | + | Step 3: + | Peek at the next-largest, and denote its width n. + | Write m = qn+r. + | If r != 0, get the node R, whose gap-width is r. + | Also, get the node QN, whose width is qn. + | Then, set M = R*QN and go to step 1. + | If r == 0, we have two cases: + | q is even: + | get/create the node for q/n, denote it T. + | Set M = T**2 and go to step 1. + | q is odd: + | get/create the node for (Q-1)*N, denote it T. + | Set M = T*N and go to step 1. The r == 0 case in step 3 is equivalent to binary exponentiation. """ From f7c0fa28e279a7c357439eb2b977f558d96dd6aa Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:32:29 +0200 Subject: [PATCH 541/665] number_field.totallyreal_*: rst fixes --- .../rings/number_field/totallyreal_data.pyx | 99 ++++++++++++------- .../rings/number_field/totallyreal_phc.py | 34 ++++--- 2 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/sage/rings/number_field/totallyreal_data.pyx b/src/sage/rings/number_field/totallyreal_data.pyx index 24476aecc0f..be2156b90d9 100644 --- a/src/sage/rings/number_field/totallyreal_data.pyx +++ b/src/sage/rings/number_field/totallyreal_data.pyx @@ -2,14 +2,15 @@ Enumeration of Totally Real Fields AUTHORS: - -- Craig Citro and John Voight (2007-11-04): - * Type checking and other polishing. - -- John Voight (2007-10-09): - * Improvements: Smyth bound, Lagrange multipliers for b. - -- John Voight (2007-09-19): - * Various optimization tweaks. - -- John Voight (2007-09-01): - * Initial version. + +- Craig Citro and John Voight (2007-11-04): + Type checking and other polishing. +- John Voight (2007-10-09): + Improvements: Smyth bound, Lagrange multipliers for b. +- John Voight (2007-09-19): + Various optimization tweaks. +- John Voight (2007-09-01): + Initial version. """ #***************************************************************************** @@ -50,12 +51,17 @@ def hermite_constant(n): r""" This function returns the nth Hermite constant - The nth Hermite constant (typically denoted $gamma_n$), is defined - to be $$ \max_L \min_{0 \neq x \in L} ||x||^2 $$ where $L$ runs - over all lattices of dimension $n$ and determinant $1$. + The nth Hermite constant (typically denoted `\gamma_n`), is defined + to be + + .. math:: + + \max_L \min_{0 \neq x \in L} ||x||^2 + + where `L` runs over all lattices of dimension `n` and determinant `1`. - For $n \leq 8$ it returns the exact value of $\gamma_n$, and for - $n > 9$ it returns an upper bound on $\gamma_n$. + For `n \leq 8` it returns the exact value of `\gamma_n`, and for + `n > 9` it returns an upper bound on `\gamma_n`. INPUT: @@ -118,7 +124,10 @@ def hermite_constant(n): cdef double eval_seq_as_poly(int *f, int n, double x): r""" Evaluates the sequence a, thought of as a polynomial with - $$ f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. $$ + + .. math:: + + f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. """ cdef double s, xp @@ -135,7 +144,11 @@ cdef double newton(int *f, int *df, int n, double x0, double eps): with provable precision eps, i.e. |x-z| < eps where z is the actual root. The sequence a corresponds to the polynomial f with - $$ f(x) = x^n + a[n-1]*x^(n-1) + ... + a[0]. $$ + + .. math:: + + f(x) = x^n + a[n-1]*x^(n-1) + ... + a[0]. + This function (for speed reasons) has no error checking and no guarantees are made as to the convergence; a naive Newton-Raphson method is used. @@ -173,7 +186,9 @@ cdef void newton_in_intervals(int *f, int *df, int n, double *beta, double eps, double *rts): r""" Find the real roots of f in the intervals specified by beta: + (beta[0],beta[1]), (beta[1],beta[2]), ..., (beta[n-1], beta[n]) + Calls newton_kernel, so same provisos apply---in particular, each interval should contain a unique simple root. Note the derivative *df is passed but is recomputed--this is @@ -190,7 +205,9 @@ cpdef lagrange_degree_3(int n, int an1, int an2, int an3): r""" Private function. Solves the equations which arise in the Lagrange multiplier for degree 3: for each 1 <= r <= n-2, we solve + r*x^i + (n-1-r)*y^i + z^i = s_i (i = 1,2,3) + where the s_i are the power sums determined by the coefficients a. We output the largest value of z which occurs. We use a precomputed elimination ideal. @@ -315,7 +332,8 @@ def int_has_small_square_divisor(sage.rings.integer.Integer d): r""" Returns the largest a such that a^2 divides d and a has prime divisors < 200. - EXAMPLES: + EXAMPLES:: + sage: from sage.rings.number_field.totallyreal_data import int_has_small_square_divisor sage: int_has_small_square_divisor(500) 100 @@ -341,7 +359,10 @@ def int_has_small_square_divisor(sage.rings.integer.Integer d): cdef int eval_seq_as_poly_int(int *f, int n, int x): r""" Evaluates the sequence a, thought of as a polynomial with - $$ f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. $$ + + .. math:: + + f[n]*x^n + f[n-1]*x^(n-1) + ... + f[0]. """ cdef int s, xp @@ -402,7 +423,8 @@ def easy_is_irreducible_py(f): """ Used solely for testing easy_is_irreducible. - EXAMPLES: + EXAMPLES:: + sage: sage.rings.number_field.totallyreal_data.easy_is_irreducible_py(pari('x^2+1')) 1 sage: sage.rings.number_field.totallyreal_data.easy_is_irreducible_py(pari('x^2-1')) @@ -446,17 +468,20 @@ cdef class tr_data: Initialization routine (constructor). INPUT: + n -- integer, the degree B -- integer, the discriminant bound a -- list (default: []), the coefficient list to begin with, where a[len(a)]*x^n + ... + a[0]x^(n-len(a)) OUTPUT: + the data initialized to begin enumeration of totally real fields with degree n, discriminant bounded by B, and starting with coefficients a. - EXAMPLES: + EXAMPLES:: + sage: T = sage.rings.number_field.totallyreal_data.tr_data(2,100) sage: T.printa() k = 0 @@ -579,16 +604,19 @@ cdef class tr_data: polynomial. INPUT: - verbose -- boolean to print verbosely computational details - haltk -- integer, the level at which to halt the inductive - coefficient bounds - phc -- boolean, if PHCPACK is available, use it when k == n-5 to - compute an improved Lagrange multiplier bound + + - verbose -- boolean to print verbosely computational details + - haltk -- integer, the level at which to halt the inductive + coefficient bounds + - phc -- boolean, if PHCPACK is available, use it when k == n-5 to + compute an improved Lagrange multiplier bound OUTPUT: - The next polynomial, as a sequence of integers - EXAMPLES: + The next polynomial, as a sequence of integers + + EXAMPLES:: + sage: T = sage.rings.number_field.totallyreal_data.tr_data(2,100) sage: T.increment() [-24, -1, 1] @@ -632,15 +660,17 @@ cdef class tr_data: polynomial. INPUT: - f_out -- an integer sequence, to be written with the - coefficients of the next polynomial - verbose -- boolean to print verbosely computational details - haltk -- integer, the level at which to halt the inductive - coefficient bounds - phc -- boolean, if PHCPACK is available, use it when k == n-5 to - compute an improved Lagrange multiplier bound + + - f_out -- an integer sequence, to be written with the coefficients of + the next polynomial + - verbose -- boolean to print verbosely computational details + - haltk -- integer, the level at which to halt the inductive + coefficient bounds + - phc -- boolean, if PHCPACK is available, use it when k == n-5 to + compute an improved Lagrange multiplier bound OUTPUT: + None. The return value is stored in the variable f_out. """ @@ -890,7 +920,8 @@ cdef class tr_data: """ Print relevant data for self. - EXAMPLES: + EXAMPLES:: + sage: T = sage.rings.number_field.totallyreal_data.tr_data(3,2^10) sage: T.printa() k = 1 diff --git a/src/sage/rings/number_field/totallyreal_phc.py b/src/sage/rings/number_field/totallyreal_phc.py index dd62402a3d5..39bc8c69105 100644 --- a/src/sage/rings/number_field/totallyreal_phc.py +++ b/src/sage/rings/number_field/totallyreal_phc.py @@ -2,6 +2,7 @@ Enumeration of Totally Real Fields: PHC interface AUTHORS: + -- John Voight (2007-10-10): * Zeroth attempt. """ @@ -30,19 +31,24 @@ def coefficients_to_power_sums(n, m, a): of the roots of f up to (m-1)th powers. INPUT: - n -- integer, the degree - a -- list of integers, the coefficients + + - n -- integer, the degree + - a -- list of integers, the coefficients OUTPUT: + list of integers. NOTES: + Uses Newton's relations, which are classical. AUTHORS: + - John Voight (2007-09-19) - EXAMPLES: + EXAMPLES:: + sage: sage.rings.number_field.totallyreal_phc.coefficients_to_power_sums(3,2,[1,5,7]) [3, -7, 39] sage: sage.rings.number_field.totallyreal_phc.coefficients_to_power_sums(5,4,[1,5,7,9,8]) @@ -65,25 +71,31 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): further information. INPUT: - k -- integer, the index of the next coefficient - a -- list of integers, the coefficients + + - k -- integer, the index of the next coefficient + - a -- list of integers, the coefficients OUTPUT: + the lower and upper bounds as real numbers. NOTES: - See Cohen [C] for the general idea and unpublished work of the + + See Cohen [Cohen2000]_ for the general idea and unpublished work of the author for more detail. - REFERENCES: - [C] Henri Cohen, Advanced topics in computational number - theory, Graduate Texts in Mathematics, vol. 193, - Springer-Verlag, New York, 2000. + REFERENCES: + + .. [Cohen2000] Henri Cohen, Advanced topics in computational number theory, + Graduate Texts in Mathematics, vol. 193, Springer-Verlag, New York, + 2000. AUTHORS: + - John Voight (2007-09-19) - EXAMPLES: + EXAMPLES:: + sage: from sage.rings.number_field.totallyreal_phc import __lagrange_bounds_phc sage: __lagrange_bounds_phc(3,5,[8,1,2,0,1]) # optional [] From 9ed1b1761ebec882caf8ee2cc3346e6039883420 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:34:01 +0200 Subject: [PATCH 542/665] sage.rings.bern*: rst fixes --- src/sage/rings/bernmm.pyx | 22 ++++++++++++------ src/sage/rings/bernoulli_mod_p.pyx | 36 +++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/bernmm.pyx b/src/sage/rings/bernmm.pyx index a1efc92c4ac..5942ca9611e 100644 --- a/src/sage/rings/bernmm.pyx +++ b/src/sage/rings/bernmm.pyx @@ -2,6 +2,7 @@ r""" Cython wrapper for bernmm library AUTHOR: + - David Harvey (2008-06): initial version """ @@ -34,14 +35,17 @@ def bernmm_bern_rat(long k, int num_threads = 1): (Wrapper for bernmm library.) INPUT: - k -- non-negative integer - num_threads -- integer >= 1, number of threads to use + + - k -- non-negative integer + - num_threads -- integer >= 1, number of threads to use COMPLEXITY: - Pretty much quadratic in $k$. See the paper ``A multimodular algorithm - for computing Bernoulli numbers'', David Harvey, 2008, for more details. - EXAMPLES: + Pretty much quadratic in $k$. See the paper "A multimodular algorithm + for computing Bernoulli numbers", David Harvey, 2008, for more details. + + EXAMPLES:: + sage: from sage.rings.bernmm import bernmm_bern_rat sage: bernmm_bern_rat(0) @@ -57,7 +61,8 @@ def bernmm_bern_rat(long k, int num_threads = 1): sage: bernmm_bern_rat(100, 3) -94598037819122125295227433069493721872702841533066936133385696204311395415197247711/33330 - TESTS: + TESTS:: + sage: lst1 = [ bernoulli(2*k, algorithm='bernmm', num_threads=2) for k in [2932, 2957, 3443, 3962, 3973] ] sage: lst2 = [ bernoulli(2*k, algorithm='pari') for k in [2932, 2957, 3443, 3962, 3973] ] sage: lst1 == lst2 @@ -87,13 +92,16 @@ def bernmm_bern_modp(long p, long k): If $B_k$ is not $p$-integral, returns -1. INPUT: + p -- a prime k -- non-negative integer COMPLEXITY: + Pretty much linear in $p$. - EXAMPLES: + EXAMPLES:: + sage: from sage.rings.bernmm import bernmm_bern_modp sage: bernoulli(0) % 5, bernmm_bern_modp(5, 0) diff --git a/src/sage/rings/bernoulli_mod_p.pyx b/src/sage/rings/bernoulli_mod_p.pyx index eb182421cd0..9b6e31711f7 100644 --- a/src/sage/rings/bernoulli_mod_p.pyx +++ b/src/sage/rings/bernoulli_mod_p.pyx @@ -2,11 +2,12 @@ r""" Bernoulli numbers modulo p AUTHOR: - - David Harvey (2006-07-26): initial version - - William Stein (2006-07-28): some touch up. - - David Harvey (2006-08-06): new, faster algorithm, also using faster NTL interface - - David Harvey (2007-08-31): algorithm for a single Bernoulli number mod p - - David Harvey (2008-06): added interface to bernmm, removed old code + +- David Harvey (2006-07-26): initial version +- William Stein (2006-07-28): some touch up. +- David Harvey (2006-08-06): new, faster algorithm, also using faster NTL interface +- David Harvey (2007-08-31): algorithm for a single Bernoulli number mod p +- David Harvey (2008-06): added interface to bernmm, removed old code """ #***************************************************************************** @@ -46,12 +47,15 @@ def verify_bernoulli_mod_p(data): (see "Irregular Primes to One Million", Buhler et al) INPUT: + data -- list, same format as output of bernoulli_mod_p function OUTPUT: + bool -- True if checksum passed - EXAMPLES: + EXAMPLES:: + sage: from sage.rings.bernoulli_mod_p import verify_bernoulli_mod_p sage: verify_bernoulli_mod_p(bernoulli_mod_p(next_prime(3))) True @@ -62,7 +66,8 @@ def verify_bernoulli_mod_p(data): sage: verify_bernoulli_mod_p([1, 2, 3, 4, 5]) False - This one should test that long longs are working: + This one should test that long longs are working:: + sage: verify_bernoulli_mod_p(bernoulli_mod_p(next_prime(20000))) True @@ -91,19 +96,24 @@ def bernoulli_mod_p(int p): Returns the bernoulli numbers `B_0, B_2, ... B_{p-3}` modulo `p`. INPUT: + p -- integer, a prime OUTPUT: + list -- Bernoulli numbers modulo `p` as a list of integers [B(0), B(2), ... B(p-3)]. ALGORITHM: + Described in accompanying latex file. PERFORMANCE: + Should be complexity `O(p \log p)`. EXAMPLES: + Check the results against PARI's C-library implementation (that computes exact rationals) for `p = 37`:: @@ -112,11 +122,13 @@ def bernoulli_mod_p(int p): sage: [bernoulli(n) % 37 for n in xrange(0, 36, 2)] [1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2] - Boundary case: + Boundary case:: + sage: bernoulli_mod_p(3) [1] AUTHOR: + -- David Harvey (2006-08-06) """ @@ -219,13 +231,16 @@ def bernoulli_mod_p_single(long p, long k): If `B_k` is not `p`-integral, an ArithmeticError is raised. INPUT: + p -- integer, a prime k -- non-negative integer OUTPUT: + The `k`-th bernoulli number mod `p`. - EXAMPLES: + EXAMPLES:: + sage: bernoulli_mod_p_single(1009, 48) 628 sage: bernoulli(48) % 1009 @@ -254,7 +269,7 @@ def bernoulli_mod_p_single(long p, long k): ... ValueError: k must be non-negative - Check results against bernoulli_mod_p: + Check results against bernoulli_mod_p:: sage: bernoulli_mod_p(37) [1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2] @@ -282,6 +297,7 @@ def bernoulli_mod_p_single(long p, long k): [1, 6, 3] AUTHOR: + -- David Harvey (2007-08-31) -- David Harvey (2008-06): rewrote to use bernmm library From 54df1d660551ce5840d3ceefd79ba3a7fbe890bd Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 11 Apr 2015 14:23:00 +0200 Subject: [PATCH 543/665] Ref: add various missing modules to r/*rings* Also sphinxify or fix their docstrings as necessary for the reference manual to build (but not necessarily to look good). --- src/doc/en/reference/number_fields/index.rst | 5 ++++ .../en/reference/polynomial_rings/index.rst | 2 ++ .../polynomial_rings_univar.rst | 11 ++++++-- src/doc/en/reference/rings/index.rst | 28 +++++++++++++++++++ .../en/reference/rings_numerical/index.rst | 3 ++ src/doc/en/reference/rings_standard/index.rst | 1 + src/sage/rings/big_oh.py | 19 +++++++++---- src/sage/rings/contfrac.py | 2 +- src/sage/rings/factorint.pyx | 2 +- .../rings/finite_rings/hom_finite_field.pyx | 2 ++ .../finite_rings/hom_finite_field_givaro.pyx | 2 ++ .../finite_rings/hom_prime_finite_field.pyx | 2 ++ src/sage/rings/fraction_field_FpT.pyx | 2 +- src/sage/rings/misc.py | 2 ++ src/sage/rings/monomials.py | 1 + src/sage/rings/number_field/number_field.py | 10 ++----- src/sage/rings/padics/morphism.pyx | 2 ++ .../rings/polynomial/polynomial_fateman.py | 2 ++ .../polynomial/polynomial_rational_flint.pyx | 2 +- .../rings/polynomial/polynomial_zz_pex.pyx | 1 + 20 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/doc/en/reference/number_fields/index.rst b/src/doc/en/reference/number_fields/index.rst index 08d7b51dc0e..86677230043 100644 --- a/src/doc/en/reference/number_fields/index.rst +++ b/src/doc/en/reference/number_fields/index.rst @@ -20,8 +20,13 @@ Algebraic Number Fields sage/rings/number_field/unit_group sage/rings/number_field/small_primes_of_degree_one sage/rings/number_field/splitting_field + sage/rings/number_field/bdd_height + sage/rings/number_field/structure sage/rings/number_field/totallyreal sage/rings/number_field/totallyreal_rel + sage/rings/number_field/totallyreal_data + sage/rings/number_field/totallyreal_phc + sage/rings/qqbar .. include:: ../footer.txt diff --git a/src/doc/en/reference/polynomial_rings/index.rst b/src/doc/en/reference/polynomial_rings/index.rst index aee618102bc..35d416aafce 100644 --- a/src/doc/en/reference/polynomial_rings/index.rst +++ b/src/doc/en/reference/polynomial_rings/index.rst @@ -21,4 +21,6 @@ Polynomial Rings sage/rings/polynomial/convolution sage/rings/polynomial/cyclotomic + sage/rings/polynomial/plural + .. include:: ../footer.txt diff --git a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst index 4b92cc2a027..d84fd747804 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst @@ -15,6 +15,7 @@ whereas others have multiple bases. :maxdepth: 2 sage/rings/polynomial/polynomial_ring + sage/rings/polynomial/polynomial_ring_homomorphism sage/rings/polynomial/polynomial_element sage/rings/polynomial/polynomial_element_generic @@ -22,16 +23,22 @@ whereas others have multiple bases. sage/rings/polynomial/polynomial_number_field sage/rings/polynomial/polynomial_integer_dense_flint sage/rings/polynomial/polynomial_integer_dense_ntl + sage/rings/polynomial/polynomial_rational_flint sage/rings/polynomial/polynomial_zmod_flint sage/rings/polynomial/polynomial_modn_dense_ntl sage/rings/polynomial/polynomial_real_mpfr_dense sage/rings/polynomial/polynomial_singular_interface + sage/rings/polynomial/padics/polynomial_padic + sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense + sage/rings/polynomial/padics/polynomial_padic_flat + sage/rings/polynomial/polynomial_zz_pex sage/rings/polynomial/real_roots sage/rings/polynomial/complex_roots + sage/rings/polynomial/ideal sage/rings/polynomial/polynomial_quotient_ring sage/rings/polynomial/polynomial_quotient_ring_element - - + sage/rings/polynomial/polynomial_compiled + sage/rings/polynomial/polynomial_fateman diff --git a/src/doc/en/reference/rings/index.rst b/src/doc/en/reference/rings/index.rst index f718b1c4234..04a82ad65ab 100644 --- a/src/doc/en/reference/rings/index.rst +++ b/src/doc/en/reference/rings/index.rst @@ -13,8 +13,36 @@ General Rings, Ideals, and Morphisms sage/rings/infinity sage/rings/fraction_field sage/rings/fraction_field_element + sage/rings/fraction_field_FpT sage/rings/quotient_ring sage/rings/quotient_ring_element sage/rings/invariant_theory + sage/rings/bernmm + sage/rings/bernoulli_mod_p + sage/rings/big_oh + sage/rings/contfrac + sage/rings/factorint + sage/rings/fast_arith + sage/rings/misc + sage/rings/monomials + + + sage/rings/commutative_algebra + sage/rings/commutative_algebra_element + sage/rings/commutative_ring + sage/rings/commutative_ring_element + sage/rings/dedekind_domain + sage/rings/dedekind_domain_element + sage/rings/euclidean_domain + sage/rings/euclidean_domain_element + sage/rings/field + sage/rings/field_element + sage/rings/integral_domain + sage/rings/integral_domain_element + sage/rings/principal_ideal_domain + sage/rings/principal_ideal_domain_element + sage/rings/ring_element + + .. include:: ../footer.txt diff --git a/src/doc/en/reference/rings_numerical/index.rst b/src/doc/en/reference/rings_numerical/index.rst index fe7b64b9965..3addbc1b441 100644 --- a/src/doc/en/reference/rings_numerical/index.rst +++ b/src/doc/en/reference/rings_numerical/index.rst @@ -36,5 +36,8 @@ when implementations aren't otherwise available. sage/rings/complex_interval_field sage/rings/complex_interval +.. Modules depending on optional packages: +.. sage/rings/real_arb + .. include:: ../footer.txt diff --git a/src/doc/en/reference/rings_standard/index.rst b/src/doc/en/reference/rings_standard/index.rst index 0c2574444a3..9140ae87ff5 100644 --- a/src/doc/en/reference/rings_standard/index.rst +++ b/src/doc/en/reference/rings_standard/index.rst @@ -17,5 +17,6 @@ Standard Commutative Rings sage/rings/finite_rings/element_base sage/rings/universal_cyclotomic_field/universal_cyclotomic_field + sage/rings/universal_cyclotomic_field/universal_cyclotomic_field_c .. include:: ../footer.txt diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 482f94b29ee..7f0d49f541e 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -17,12 +17,15 @@ def O(*x): Big O constructor for various types. EXAMPLES: - This is useful for writing power series elements. + + This is useful for writing power series elements. :: + sage: R. = ZZ[['t']] sage: (1+t)^10 + O(t^5) 1 + 10*t + 45*t^2 + 120*t^3 + 210*t^4 + O(t^5) - A power series ring is created implicitly if a polynomial element is passed in. + A power series ring is created implicitly if a polynomial element is passed in. :: + sage: R. = QQ['x'] sage: O(x^100) O(x^100) @@ -32,23 +35,27 @@ def O(*x): sage: 1 + u + v^2 + O(u, v)^5 1 + u + v^2 + O(u, v)^5 - This is also useful to create p-adic numbers. + This is also useful to create p-adic numbers. :: + sage: O(7^6) O(7^6) sage: 1/3 + O(7^6) 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) - It behaves well with respect to adding negative powers of p: + It behaves well with respect to adding negative powers of p:: + sage: a = O(11^-32); a O(11^-32) sage: a.parent() 11-adic Field with capped relative precision 20 - There are problems if you add a rational with very negative valuation to a big_oh. + There are problems if you add a rational with very negative valuation to a big_oh. :: + sage: 11^-12 + O(11^15) 11^-12 + O(11^8) - The reason that this fails is that the O function doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue. + The reason that this fails is that the O function doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue. :: + sage: K = Qp(11, 30) sage: K(11^-12) + O(11^15) 11^-12 + O(11^15) diff --git a/src/sage/rings/contfrac.py b/src/sage/rings/contfrac.py index 101e55c5a67..19cefcc6cb1 100644 --- a/src/sage/rings/contfrac.py +++ b/src/sage/rings/contfrac.py @@ -7,7 +7,7 @@ printing and semantics. It should be possible to use this field in most cases where one could use `\QQ`, except arithmetic is *much* slower. -EXAMPLES:: +EXAMPLES: We can create matrices, polynomials, vectors, etc., over the continued fraction field:: diff --git a/src/sage/rings/factorint.pyx b/src/sage/rings/factorint.pyx index 94af838b06c..045e15e1962 100644 --- a/src/sage/rings/factorint.pyx +++ b/src/sage/rings/factorint.pyx @@ -122,7 +122,7 @@ cpdef aurifeuillian(n, m, F=None, bint check=True): cpdef factor_aurifeuillian(n, check=True): r""" - Return Aurifeuillian factors of `n` if `n = x^{(2k-1)x} \pw 1` + Return Aurifeuillian factors of `n` if `n = x^{(2k-1)x} \pm 1` (where the sign is '-' if x = 1 mod 4, and '+' otherwise) else `n` INPUT: diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index f26a999510a..04a45c10142 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -1,4 +1,6 @@ """ +Finite field morphisms + This file provides several classes implementing: - embeddings between finite fields diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx index f9e213ebb12..cbb1f0d3655 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -1,4 +1,6 @@ """ +Finite field morphisms using Givaro + Special implementation for givaro finite fields of: - embeddings between finite fields diff --git a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx index 4ae0ea4acb5..f227460a048 100644 --- a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx @@ -1,4 +1,6 @@ """ +Finite field morphisms for prime fields + Special implementation for prime finite field of: - embeddings of such field into general finite fields diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 9e19a8b8679..4759d0989c0 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -1,4 +1,4 @@ - +"Univariate rational functions over prime fields" import sys diff --git a/src/sage/rings/misc.py b/src/sage/rings/misc.py index 19d20819ad4..d84298aeee4 100644 --- a/src/sage/rings/misc.py +++ b/src/sage/rings/misc.py @@ -1,3 +1,5 @@ +"Miscellaneous utilities" + ########################################################################### # Copyright (C) 2008 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # diff --git a/src/sage/rings/monomials.py b/src/sage/rings/monomials.py index 49ba87c5b96..0beb25a1044 100644 --- a/src/sage/rings/monomials.py +++ b/src/sage/rings/monomials.py @@ -1,3 +1,4 @@ +"Monomials" def _monomials(gens, R, n, i): """ diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 27caabb0f72..bfc39e9eaf2 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8244,7 +8244,7 @@ def elements_of_bounded_height(self,bound,precision=53,LLL=False): Certain computations may be faster assuming GRH, which may be done globally by using the number_field(True/False) switch. - For details: See [Doyle-Krumm]. + For details: See [Doyle-Krumm]_. INPUT: @@ -8267,7 +8267,7 @@ def elements_of_bounded_height(self,bound,precision=53,LLL=False): .. TODO:: Should implement a version of the algorithm that guarantees correct - output. See Algorithm 4 in [Doyle-Krumm] for details of an + output. See Algorithm 4 in [Doyle-Krumm]_ for details of an implementation that takes precision issues into account. EXAMPLES: @@ -8359,12 +8359,6 @@ def elements_of_bounded_height(self,bound,precision=53,LLL=False): - John Doyle (2013) - David Krumm (2013) - - REFERENCES: - - .. [Doyle-Krumm] John R. Doyle and David Krumm, Computing algebraic - numbers of bounded height, :arxiv:`1111.4963` (2013). - """ from sage.rings.number_field.bdd_height import bdd_height, bdd_height_iq r1, r2 = self.signature() diff --git a/src/sage/rings/padics/morphism.pyx b/src/sage/rings/padics/morphism.pyx index 7eb2d2549b9..759827d1de3 100644 --- a/src/sage/rings/padics/morphism.pyx +++ b/src/sage/rings/padics/morphism.pyx @@ -1,3 +1,5 @@ +"Frobenius endomorphisms on padic fields" + ############################################################################# # Copyright (C) 2013 Xavier Caruso # diff --git a/src/sage/rings/polynomial/polynomial_fateman.py b/src/sage/rings/polynomial/polynomial_fateman.py index d2456dfd69f..536f64d4e18 100644 --- a/src/sage/rings/polynomial/polynomial_fateman.py +++ b/src/sage/rings/polynomial/polynomial_fateman.py @@ -1,3 +1,5 @@ +"Polynomial multiplication by Kronecker substitution" + ################################################################################ # Copyright (C) 2007 William Stein # diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index bae6763ad84..f476f1bd563 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -575,7 +575,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: f.reverse(5) t^4 + t^3 + 1/2*t^2 + 1/3*t - TESTS:: + TESTS: We illustrate two ways in which the interpretation of `n` as an unsigned long int may fail. Firstly, an integral value which is diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index 2d8af8af80e..549c9926605 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -2,6 +2,7 @@ Univariate Polynomials over GF(p^e) via NTL's ZZ_pEX. AUTHOR: + - Yann Laigle-Chapuy (2010-01) initial implementation """ From 6882809c60ab2eede60983a0c44964417dce48ac Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 25 Apr 2015 11:32:48 +0200 Subject: [PATCH 544/665] Trac 18283: doctest --- src/sage/combinat/words/words.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 64c28f57b92..c0022b41698 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -1632,6 +1632,12 @@ def random_element(self): TESTS:: sage: _ = Words(GF(5),4).random_element() + + Check that :trac:`18283` is fixed:: + + sage: w = Words('abc', 5).random_element() + sage: w.length() + 5 """ if self.alphabet().cardinality() == Infinity: raise ValueError("How can I pick a random word with an infinite aphabet?") From d85a98ccbbe34c2abc032c7bc18efe9af67c95e1 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 25 Apr 2015 12:15:13 +0200 Subject: [PATCH 545/665] Trac 16880: previous_prime/{next,previous}_prime_power Implementation of: - a method previous_prime using pari precprime - (naive) methods next_prime_power and previous_prime_power --- src/sage/rings/integer.pyx | 178 ++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index d8fc13805e6..c65445ac43b 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -4106,7 +4106,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): True """ return True - + def is_integer(self): """ Returns ``True`` as they are integers @@ -5093,7 +5093,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def next_prime(self, proof=None): r""" - Returns the next prime after self. + Return the next prime after self. + + This method calls the Pari ``nextprime`` function. INPUT: @@ -5128,6 +5130,178 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): p = Integer(p._pari_().nextprime(True)) return p + def previous_prime(self, proof=None): + r""" + Returns the previous prime before self. + + This method calls the Pari ``precprime`` function. + + INPUT: + + - ``proof`` - if ``True`` ensure that the returned value is the next + prime power and if set to ``False`` uses probabilistic methods + (i.e. the result is not guaranteed). By default it uses global + configuration variables to determine which alternative to use (see + :mod:`proof.arithmetic` or :mod:`sage.structure.proof`). + + .. SEEALSO: + + - :meth:`next_prime` + + EXAMPLES:: + + sage: 10.previous_prime() + 7 + sage: 7.previous_prime() + 5 + sage: 14376485.previous_prime() + 14376463 + + sage: 2.previous_prime() + Traceback (most recent call last): + ... + ValueError: no prime less than 2 + + An example using ``proof=False``, which is way faster since it does not + need a primality proof:: + + sage: b = (2^1024).previous_prime(proof=False) + sage: 2^1024 - b + 105 + """ + if mpz_cmp_ui(self.value, 2) <= 0: + raise ValueError("no prime less than 2") + cdef Integer p = self-1 + p = Integer(p._pari_().precprime()) + while not p._pseudoprime_is_prime(proof): + mpz_sub_ui(p.value, p.value, 1) + p = Integer(p._pari_().precprime()) + return p + + def next_prime_power(self, proof=None): + r""" + Return the next prime power after self. + + INPUT: + + - ``proof`` - if ``True`` ensure that the returned value is the next + prime power and if set to ``False`` uses probabilistic methods + (i.e. the result is not guaranteed). By default it uses global + configuration variables to determine which alternative to use (see + :mod:`proof.arithmetic` or :mod:`sage.structure.proof`). + + ALGORITHM: + + The algorithm is naive. It computes the next power of 2 and go through + the odd numbers calling :meth:`is_prime_power`. + + .. SEEALSO:: + + - :meth:`previous_prime_power` + - :meth:`is_prime_power` + - :meth:`next_prime` + - :meth:`previous_prime` + + EXAMPLES:: + + sage: (-1).next_prime_power() + 2 + sage: 2.next_prime_power() + 3 + sage: 103.next_prime_power() + 107 + sage: 107.next_prime_power() + 109 + sage: 2044.next_prime_power() + 2048 + """ + cdef Integer n = PY_NEW(Integer) + + mpz_set(n.value, self.value) + if mpz_cmp_ui(n.value, 2) < 0: + mpz_set_ui(n.value, 2) + return n + + mpz_add_ui(n.value, n.value, 1) + if mpz_even_p(n.value): + if n.is_prime_power(proof=proof): + return n + mpz_add_ui(n.value, n.value, 1) + + # the next power of 2 + cdef Integer m = PY_NEW(Integer) + mpz_set_ui(m.value, 1) + mpz_mul_2exp(m.value, m.value, mpz_sizeinbase(n.value,2)) + + while mpz_cmp(m.value, n.value) == 1: + if n.is_prime_power(proof=proof): + return n + mpz_add_ui(n.value, n.value, 2) + return m + + def previous_prime_power(self, proof=None): + r""" + Return the previous prime power before self. + + INPUT: + + - ``proof`` - if ``True`` ensure that the returned value is the next + prime power and if set to ``False`` uses probabilistic methods + (i.e. the result is not guaranteed). By default it uses global + configuration variables to determine which alternative to use (see + :mod:`proof.arithmetic` or :mod:`sage.structure.proof`). + + ALGORITHM: + + The algorithm is naive. It computes the previous power of 2 and go + through the odd numbers calling the method :meth:`is_prime_power`. + + .. SEEALSO:: + + - :meth:`next_prime_power` + - :meth:`is_prime_power` + - :meth:`previous_prime` + - :meth:`next_prime` + + EXAMPLES:: + + sage: 3.previous_prime_power() + 2 + sage: 103.previous_prime_power() + 101 + sage: 107.previous_prime_power() + 103 + sage: 2044.previous_prime_power() + 2039 + + sage: 2.previous_prime_power() + Traceback (most recent call last): + ... + ValueError: no prime power less than 2 + """ + if mpz_cmp_ui(self.value, 2) <= 0: + raise ValueError("no prime power less than 2") + + cdef Integer n = PY_NEW(Integer) + + mpz_set(n.value, self.value) + mpz_sub_ui(n.value, n.value, 1) + if mpz_even_p(n.value): + if n.is_prime_power(proof=proof): + return n + mpz_sub_ui(n.value, n.value, 1) + + # the previous power of 2 + cdef Integer m = PY_NEW(Integer) + mpz_set_ui(m.value, 1) + mpz_mul_2exp(m.value, m.value, mpz_sizeinbase(n.value,2)-1) + + while mpz_cmp(m.value, n.value) == -1: + if n.is_prime_power(proof=proof): + return n + mpz_sub_ui(n.value, n.value, 2) + return m + def additive_order(self): """ Return the additive order of self. From db1e869640dbb20d39e565970aaa8c5d58fa8953 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 25 Apr 2015 12:46:57 +0200 Subject: [PATCH 546/665] Trac 16880: make rings.arith uses the new methods --- src/sage/rings/arith.py | 108 ++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 27 deletions(-) diff --git a/src/sage/rings/arith.py b/src/sage/rings/arith.py index bf47f5eec48..ff083a0ea02 100644 --- a/src/sage/rings/arith.py +++ b/src/sage/rings/arith.py @@ -482,6 +482,9 @@ def is_prime_power(n, flag=None, get_data=False): r""" Test whether ``n`` is a positive power of a prime number + This function simply calls the method :meth:`Integer.is_prime_power() + ` of Integers. + INPUT: - ``n`` -- an integer @@ -503,6 +506,21 @@ def is_prime_power(n, flag=None, get_data=False): sage: is_prime_power(1024, get_data=True) (2, 10) + The same results can be obtained with:: + + sage: 389.is_prime_power() + True + sage: 2000.is_prime_power() + False + sage: 2.is_prime_power() + True + sage: 1024.is_prime_power() + True + sage: 1024.is_prime_power(get_data=True) + (2, 10) + + TESTS:: + sage: is_prime_power(-1) False sage: is_prime_power(1) @@ -933,16 +951,24 @@ def primes(start, stop=None, proof=None): def next_prime_power(n): """ - The next prime power greater than the integer n. If n is a prime - power, then this function does not return n, but the next prime - power after n. + Return the smallest prime power greater than ``n``. + + Note that if ``n`` is a prime power, then this function does not return + ``n``, but the next prime power after ``n``. + + This function just calls the method + :meth:`Integer.next_prime_power() ` + of Integers. + + .. SEEALSO:: + + - :func:`is_prime_power` (and + :meth:`Integer.is_prime_power() `) + - :func:`previous_prime_power` (and + :meth:`Integer.previous_prime_power() `) EXAMPLES:: - sage: next_prime_power(-10) - 2 - sage: next_prime_power(0) - 2 sage: next_prime_power(1) 2 sage: next_prime_power(2) @@ -953,13 +979,24 @@ def next_prime_power(n): 8 sage: next_prime_power(99) 101 + + The same results can be obtained with:: + + sage: 1.next_prime_power() + 2 + sage: 2.next_prime_power() + 3 + sage: 10.next_prime_power() + 11 + + Note that `2` is the smallest prime power:: + + sage: next_prime_power(-10) + 2 + sage: next_prime_power(0) + 2 """ - n = ZZ(n) + 1 - if n <= 2: # negatives are not prime. - return ZZ(2) - while not n.is_prime_power(): - n += 1 - return n + return ZZ(n).next_prime_power() def next_probable_prime(n): """ @@ -1069,10 +1106,21 @@ def previous_prime(n): def previous_prime_power(n): r""" - The largest prime power `< n`. The result is provably - correct. If `n \leq 2`, this function returns `-x`, - where `x` is prime power and `-x < n` and no larger - negative of a prime power has this property. + Return the largest prime power smaller than ``n``. + + The result is provably correct. If ``n`` is smaller or equal than ``2`` this + function raises an error. + + This function simply call the method + :meth:`Integer.previous_prime_power() ` + of Integers. + + .. SEEALSO:: + + - :func:`is_prime_power` (and :meth:`Integer.is_prime_power() + `) + - :func:`next_prime_power` (and :meth:`Integer.next_prime_power() + `) EXAMPLES:: @@ -1085,31 +1133,37 @@ def previous_prime_power(n): sage: previous_prime_power(127) 125 - :: + The same results can be obtained with:: + + sage: 3.previous_prime_power() + 2 + sage: 10.previous_prime_power() + 9 + sage: 7.previous_prime_power() + 5 + sage: 127.previous_prime_power() + 125 + + Input lesser or equal than `2` raises errors:: sage: previous_prime_power(2) Traceback (most recent call last): ... - ValueError: no previous prime power + ValueError: no prime power less than 2 sage: previous_prime_power(-10) Traceback (most recent call last): ... - ValueError: no previous prime power + ValueError: no prime power less than 2 :: sage: n = previous_prime_power(2^16 - 1) sage: while is_prime(n): - ....: n = previous_prime_power(n) + ....: n = previous_prime_power(n) sage: factor(n) 251^2 """ - n = ZZ(n) - 1 - if n <= 1: - raise ValueError("no previous prime power") - while not is_prime_power(n): - n -= 1 - return n + return ZZ(n).previous_prime_power() def random_prime(n, proof=None, lbound=2): """ From 6494c992ba24981bfaf47d3b83df145d03fd81d5 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sat, 25 Apr 2015 12:58:52 +0200 Subject: [PATCH 547/665] Trac 18297: increase doctest tolerance --- src/doc/en/thematic_tutorials/linear_programming.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/thematic_tutorials/linear_programming.rst b/src/doc/en/thematic_tutorials/linear_programming.rst index 78c6a16a476..773c3772f6d 100644 --- a/src/doc/en/thematic_tutorials/linear_programming.rst +++ b/src/doc/en/thematic_tutorials/linear_programming.rst @@ -429,7 +429,7 @@ graph, in which all the edges have a capacity of 1:: :: - sage: p.solve() # rel tol 2e-12 + sage: p.solve() # rel tol 2e-11 2.0 .. image:: media/lp_flot2.png From 4a2762124176ee5b69a6bf55bd2734b1cc5560e0 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 13 Apr 2015 15:05:22 +0200 Subject: [PATCH 548/665] #9903 document effect of global proof flag in is_prime --- src/sage/rings/arith.py | 16 ++++++++++++---- src/sage/rings/integer.pyx | 6 ++++-- src/sage/sets/set_from_iterator.py | 3 +-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/arith.py b/src/sage/rings/arith.py index d8e673e9696..5671ef51d9b 100644 --- a/src/sage/rings/arith.py +++ b/src/sage/rings/arith.py @@ -408,15 +408,23 @@ def is_prime(n): r""" Return ``True`` if `n` is a prime number, and ``False`` otherwise. - AUTHORS: - - - Kevin Stueve kstueve@uw.edu (2010-01-17): - delegated calculation to ``n.is_prime()`` + Use a provable primality test or a strong pseudo-primality test depending + on the global :mod:`arithmetic proof flag `. INPUT: - ``n`` - the object for which to determine primality + .. SEEALSO:: + + - :meth:`is_pseudoprime` + - :meth:`sage.rings.integer.Integer.is_prime` + + AUTHORS: + + - Kevin Stueve kstueve@uw.edu (2010-01-17): + delegated calculation to ``n.is_prime()`` + EXAMPLES:: sage: is_prime(389) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index f7b4dbe819e..1d6778a6da2 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -4581,7 +4581,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``proof`` -- Boolean or ``None`` (default). If False, use a strong pseudo-primality test (see :meth:`is_pseudoprime`). If True, use a provable primality test. If unset, use the - default arithmetic proof flag. + :mod:`default arithmetic proof flag `. .. note:: @@ -4628,7 +4628,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: timeit("n.is_prime()") # not tested 1000 loops, best of 3: 573 us per loop - IMPLEMENTATION: Calls the PARI ``isprime`` function. + ALGORITHM: + + Calls the PARI ``isprime`` function. """ if mpz_sgn(self.value) <= 0: return False diff --git a/src/sage/sets/set_from_iterator.py b/src/sage/sets/set_from_iterator.py index ed4389885a4..402de8738fa 100644 --- a/src/sage/sets/set_from_iterator.py +++ b/src/sage/sets/set_from_iterator.py @@ -443,8 +443,7 @@ def _sage_doc_(self): sage: print sage_getdoc(d) # indirect doctest Test whether "self" is prime. ... - IMPLEMENTATION: Calls the PARI "isprime" function. - + Calls the PARI "isprime" function. """ from sage.misc.sageinspect import sage_getsourcelines, sage_getfile, _extract_embedded_position f = self.f From 7b687fdf9f2b966fdc34c6214b580d5affe4b942 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 22 Apr 2015 15:02:11 +0200 Subject: [PATCH 549/665] #9903 additional example --- src/sage/rings/arith.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/rings/arith.py b/src/sage/rings/arith.py index 5671ef51d9b..019bcb29ffd 100644 --- a/src/sage/rings/arith.py +++ b/src/sage/rings/arith.py @@ -439,6 +439,13 @@ def is_prime(n): False sage: is_prime(-2) False + + sage: a = 2**2048 + 981 + sage: is_prime(a) # not tested - takes ~ 1min + sage: proof.arithmetic(False) + sage: is_prime(a) # instantaneous! + True + sage: proof.arithmetic(True) """ try: return n.is_prime() From 723a55c71861db896335aa75763e8bba85a2a3b0 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Sat, 25 Apr 2015 14:11:57 +0200 Subject: [PATCH 550/665] Replaced __repr__ by _repr_ --- src/sage/coding/channel_constructions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index becf2a85247..7ad27802dd2 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -83,7 +83,7 @@ class Channel(SageObject): - override :meth:`transmit_unsafe`. - While not being mandatory, it might be useful to reimplement representation methods (``__repr__`` and + While not being mandatory, it might be useful to reimplement representation methods (``_repr_`` and ``_latex_``). This abstract class provides the following parameters: @@ -303,7 +303,7 @@ def __init__(self, space, number_errors): raise ValueError("There might be more errors than the dimension of the input space") self._number_errors = number_errors - def __repr__(self): + def _repr_(self): r""" Returns a string representation of ``self``. @@ -490,7 +490,7 @@ def __init__(self, space, number_errors, number_erasures): self._number_errors = number_errors self._number_erasures = number_erasures - def __repr__(self): + def _repr_(self): r""" Returns a string representation of ``self``. From 47226ff02d2c7de7032dfca2073186bd5f9edf8b Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sat, 25 Apr 2015 07:05:44 -0700 Subject: [PATCH 551/665] minor docfix --- .../combinat/root_system/integrable_representations.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 2add6b426e0..56fb4d8af11 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -55,10 +55,9 @@ class IntegrableRepresentation(CategoryObject, UniqueRepresentation): (\Lambda+\rho | \Lambda+\rho) - (\mu+\rho | \mu+\rho) \geq 0 where `(\, | \,)` is the invariant inner product on the weight - lattice and `\rho` is the Weyl vector. Moreover every `\mu` differs from - `\Lambda` by an element of the root lattice. ([Kac]_, Propositions 11.3 - and 11.4) such that `\Lambda - \mu` is in the root lattice, then - multiplicity of `\mu` in this representation will be denoted `m(\mu)`. + lattice and `\rho` is the Weyl vector. Moreover if `m(\mu)>0` + then `\mu\in\operatorname{supp}(V)` differs from `\Lambda` by an element + of the root lattice ([Kac]_, Propositions 11.3 and 11.4). Let `\delta` be the nullroot, which is the lowest positive imaginary root. Then by [Kac]_, Proposition 11.3 or Corollary 11.9, for fixed `\mu` @@ -489,7 +488,7 @@ def _from_weight_helper(self, mu, check=False): def from_weight(self, mu): r""" Return the tuple `(n_0, n_1, ...)`` such that ``mu`` equals - `\Lambda - sum_{i \in I} n_i \alpha_i` in ``self``, where `\Lambda` + `\Lambda - \sum_{i \in I} n_i \alpha_i` in ``self``, where `\Lambda` is the highest weight of ``self``. EXAMPLES:: From ccc6e3dc31ca4299a679efe4881988afb1f4961d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 25 Apr 2015 17:46:00 +0200 Subject: [PATCH 552/665] trac #9123 correct one --- src/sage/algebras/schur_algebra.py | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 6e1486abb85..1afb27ba71a 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -31,22 +31,24 @@ from sage.categories.all import AlgebrasWithBasis +from sage.categories.rings import Rings from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.integer_list import IntegerListsLex +from sage.combinat.partition import Partitions, Partition from sage.combinat.permutation import Permutations -from copy import copy -from sage.categories.rings import Rings -from sage.rings.integer import Integer -from sage.misc.cachefunc import cached_method from sage.combinat.sf.sf import SymmetricFunctions -from sage.rings.rational_field import QQ +from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra +from sage.combinat.tableau import SemistandardTableaux from sage.combinat.words.word import Word from sage.combinat.words.words import Words -from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.combinat.tableau import SemistandardTableaux -from sage.misc.flatten import flatten -from sage.combinat.partition import Partitions, Partition from sage.matrix.constructor import Matrix +from sage.misc.cachefunc import cached_method +from sage.misc.flatten import flatten +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ + +from copy import copy def _schur_I_nr_representatives(n, r, element, index): @@ -224,23 +226,27 @@ def _repr_(self): sage: repr(S) 'Schur Algebra (4,4) over Integer Ring' """ - return "Schur Algebra (%s,%s) over %s" % (self._n, self._r, - self.base_ring()) + msg = "Schur Algebra ({},{}) over {}" + return msg.format(self._n, self._r, self.base_ring()) @cached_method - def one_basis(self): + def one(self): """ - Return the index of the one of the algebra. - - THIS IS WRONG ! + Return the one of the algebra. EXAMPLES:: sage: from sage.algebras.all import SchurAlgebra - sage: SchurAlgebra(4, 4, ZZ).one() # indirect doctest - B[None] + sage: S = SchurAlgebra(4, 4, ZZ) + sage: e = S.one() + sage: x = S.an_element() + sage: x * e == x + True """ - return None + tt = IntegerListsLex(length=self._r, min_part=1, max_part=self._n, + min_slope=0) + words = [Word(u) for u in tt] + return self.sum(self._monomial((w, w)) for w in words) def product_on_basis(self, e_ij, e_kl): r""" From 9b48fec116a29a3449c816bcf392ce3d07e72667 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 25 Apr 2015 20:49:40 +0200 Subject: [PATCH 553/665] Doctest .pxd files also --- src/sage/doctest/control.py | 2 +- src/sage/doctest/sources.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 2fd11b3b3c9..2381d7988de 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -168,7 +168,7 @@ def skipfile(filename): True """ base, ext = os.path.splitext(filename) - if ext not in ('.py', '.pyx', '.pxi', '.sage', '.spyx', '.rst', '.tex'): + if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex'): return True with open(filename) as F: line_count = 0 diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index b4e43eae12b..aa953aa1e89 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -483,12 +483,14 @@ def __init__(self, path, options): self.path = path DocTestSource.__init__(self, options) base, ext = os.path.splitext(path) - if ext in ('.py', '.pyx', '.pxi', '.sage', '.spyx'): + if ext in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx'): self.__class__ = dynamic_class('PythonFileSource',(FileDocTestSource,PythonSource)) elif ext == '.tex': self.__class__ = dynamic_class('TexFileSource',(FileDocTestSource,TexSource)) elif ext == '.rst': self.__class__ = dynamic_class('RestFileSource',(FileDocTestSource,RestSource)) + else: + raise ValueError("unknown file extension %r"%ext) def __iter__(self): r""" @@ -694,7 +696,7 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): ....: dirs.sort(); files.sort() ....: for F in files: ....: _, ext = os.path.splitext(F) - ....: if ext in ('.py', '.pyx', '.pxi', '.sage', '.spyx', '.rst'): + ....: if ext in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst'): ....: filename = os.path.join(path, F) ....: FDS = FileDocTestSource(filename, DocTestDefaults(long=True,optional=True)) ....: FDS._test_enough_doctests(verbose=False) From 1ad339bf0c8ffe75d23ddaa6d896121b8c96636d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 25 Apr 2015 20:45:35 +0200 Subject: [PATCH 554/665] Implement _rich_to_bool as inline function instead of member function --- src/sage/libs/ecl.pyx | 15 +--- src/sage/libs/pari/gen.pyx | 3 +- src/sage/rings/integer.pyx | 4 +- .../number_field_element_quadratic.pyx | 17 ++--- src/sage/structure/element.pxd | 1 - src/sage/structure/element.pyx | 34 +++------ src/sage/structure/parent.pyx | 16 +---- src/sage/structure/sage_object.pxd | 71 +++++++++++++++++++ 8 files changed, 93 insertions(+), 68 deletions(-) diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index d685145ac56..47bbf1628cd 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -828,20 +828,7 @@ cdef class EclObject: #and does not have generic routines for doing that. #we could dispatch based on type here, but that seems #inappropriate for an *interface*. - raise NotImplementedError,"EclObjects can only be compared for equality" - - #if not(isinstance(left,EclObject)) or not(isinstance(right,EclObject)): - # raise TypeError,"Can only compare EclObjects" - #if op == 0: # "<" - # pass - #elif op == 1: # "<=" - # pass - #elif op == 4: # ">" - # pass - #elif op == 5: # ">=" - # pass - #else: - # raise ValueError,"richcmp received operation code %d"%op + raise NotImplementedError("EclObjects can only be compared for equality") def __iter__(self): r""" diff --git a/src/sage/libs/pari/gen.pyx b/src/sage/libs/pari/gen.pyx index 985d3ba2585..f587a2fec9d 100644 --- a/src/sage/libs/pari/gen.pyx +++ b/src/sage/libs/pari/gen.pyx @@ -54,6 +54,7 @@ import operator import sage.structure.element from sage.structure.element cimport ModuleElement, RingElement, Element from sage.misc.randstate cimport randstate, current_randstate +from sage.structure.sage_object cimport rich_to_bool include 'pari_err.pxi' include 'sage/ext/stdsage.pxi' @@ -1122,7 +1123,7 @@ cdef class gen(gen_auto): elif op == 3: # != r = (gequal(x, y) == 0) else: - r = left._rich_to_bool(op, gcmp(x, y)) + r = rich_to_bool(op, gcmp(x, y)) pari_catch_sig_off() return r diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 299878d2edc..27904a3f798 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -320,7 +320,7 @@ cdef _digits_internal(mpz_t v,l,int offset,int power_index,power_list,digits): mpz_clear(mpz_quot) mpz_clear(mpz_res) -from sage.structure.sage_object cimport SageObject +from sage.structure.sage_object cimport SageObject, rich_to_bool_sgn from sage.structure.element cimport EuclideanDomainElement, ModuleElement, Element from sage.structure.element import bin_op from sage.structure.coerce_exceptions import CoercionException @@ -891,7 +891,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): c = -mpz_cmp_d((right).value, d) else: return (left)._richcmp(right, op) - return (left)._rich_to_bool(op, c) + return rich_to_bool_sgn(op, c) cpdef int _cmp_(left, sage.structure.element.Element right) except -2: cdef int i diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 98635c2da43..66337bfb264 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -36,6 +36,7 @@ include "sage/ext/interrupt.pxi" include "sage/ext/stdsage.pxi" from sage.structure.element cimport Element +from sage.structure.sage_object cimport rich_to_bool_sgn from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -46,14 +47,6 @@ from sage.rings.number_field.number_field_element import _inverse_mod_generic import number_field -# TODO: this doesn't belong here, but robert thinks it would be nice -# to have globally available.... -# -# cdef mpz_to_str(mpz_t z): -# cdef Integer zz = PY_NEW(Integer) -# mpz_set(zz.value, z) -# return str(zz) - def __make_NumberFieldElement_quadratic0(parent, a, b, denom): """ @@ -762,7 +755,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): if test: mpz_clear(i) mpz_clear(j) - return (left)._rich_to_bool(op, test) + return rich_to_bool_sgn(op, test) mpz_mul(i, left.b, right.denom) mpz_mul(j, right.b, left.denom) test = mpz_cmp(i,j) @@ -771,11 +764,11 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): test = -test mpz_clear(i) mpz_clear(j) - return (left)._rich_to_bool(op, test) + return rich_to_bool_sgn(op, test) test = mpz_cmp(left.denom, right.denom) mpz_clear(i) mpz_clear(j) - return (left)._rich_to_bool(op, test) + return rich_to_bool_sgn(op, test) # comparison in the real case mpz_init(i) @@ -809,7 +802,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_clear(i) mpz_clear(j) - return (left)._rich_to_bool(op, test) + return rich_to_bool_sgn(op, test) def __cmp__(left, right): r""" diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 90607dfa6f2..f31de488b54 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -40,7 +40,6 @@ cdef class Element(SageObject): cdef _cmp(self, right) cdef _set_parent_c(self, Parent parent) cpdef base_extend(self, R) - cdef _rich_to_bool(self, int op, int r) cpdef _act_on_(self, x, bint self_on_left) cpdef _acted_upon_(self, x, bint self_on_left) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 86649a62ef3..d1c17558419 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -160,6 +160,7 @@ from operator import add, sub, mul, div, iadd, isub, imul, idiv cdef MethodType from types import MethodType +from sage.structure.sage_object cimport rich_to_bool from sage.structure.coerce cimport py_scalar_to_element from sage.structure.parent cimport Parent from sage.structure.misc import is_extension_type, getattr_from_other_class @@ -938,14 +939,14 @@ cdef class Element(SageObject): cdef int r if not have_same_parent_c(left, right): if left is None or left is Ellipsis: - return _rich_to_bool(op, -1) + return rich_to_bool(op, -1) elif right is None or right is Ellipsis: - return _rich_to_bool(op, 1) + return rich_to_bool(op, 1) try: _left, _right = coercion_model.canonical_coercion(left, right) if isinstance(_left, Element): return (_left)._richcmp(_right, op) - return _rich_to_bool(op, cmp(_left, _right)) + return rich_to_bool(op, cmp(_left, _right)) except (TypeError, NotImplementedError): r = cmp(type(left), type(right)) if r == 0: @@ -964,16 +965,13 @@ cdef class Element(SageObject): elif isinstance(right, Element) and isinstance(left, (int, float, Integer)) and not left: left = (right)._parent(left) else: - return _rich_to_bool(op, r) + return rich_to_bool(op, r) except TypeError: - return _rich_to_bool(op, r) + return rich_to_bool(op, r) # Same parents return left._richcmp_(right, op) - cdef _rich_to_bool(self, int op, int r): - return _rich_to_bool(op, r) - #################################################################### # For a derived Cython class, you **must** put the __richcmp__ # method below in your subclasses, in order for it to take @@ -997,7 +995,7 @@ cdef class Element(SageObject): cpdef _richcmp_(left, Element right, int op): # Obvious case if left is right: - return _rich_to_bool(op, 0) + return rich_to_bool(op, 0) cdef int c try: @@ -1007,7 +1005,8 @@ cdef class Element(SageObject): if op == Py_EQ: return False if op == Py_NE: return True raise - return _rich_to_bool(op, c) + assert -1 <= c <= 1 + return rich_to_bool(op, c) cpdef int _cmp_(left, Element right) except -2: # Check for Python class defining __cmp__ @@ -1017,21 +1016,6 @@ cdef class Element(SageObject): raise NotImplementedError("comparison not implemented for %r"%type(left)) -cdef inline bint _rich_to_bool(int op, int r): - if op == Py_LT: #< - return (r < 0) - elif op == Py_EQ: #== - return (r == 0) - elif op == Py_GT: #> - return (r > 0) - elif op == Py_LE: #<= - return (r <= 0) - elif op == Py_NE: #!= - return (r != 0) - elif op == Py_GE: #>= - return (r >= 0) - - def is_ModuleElement(x): """ Return ``True`` if x is of type ModuleElement. diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 7c48d2f2bc4..9f4e4aa5bed 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -99,7 +99,7 @@ from element cimport parent_c cimport sage.categories.morphism as morphism cimport sage.categories.map as map from sage.structure.debug_options import debug -from sage.structure.sage_object import SageObject +from sage.structure.sage_object cimport SageObject, rich_to_bool from sage.structure.misc import (dir_with_other_class, getattr_from_other_class, is_extension_type) from sage.misc.lazy_attribute import lazy_attribute @@ -1500,18 +1500,8 @@ cdef class Parent(category_object.CategoryObject): # Both are parents -- but need *not* have the same type. r = left._cmp_(right) - if op == 0: #< - return r < 0 - elif op == 2: #== - return r == 0 - elif op == 4: #> - return r > 0 - elif op == 1: #<= - return r <= 0 - elif op == 3: #!= - return r != 0 - elif op == 5: #>= - return r >= 0 + assert -1 <= r <= 1 + return rich_to_bool(op, r) cpdef int _cmp_(left, right) except -2: # Check for Python class defining __cmp__ diff --git a/src/sage/structure/sage_object.pxd b/src/sage/structure/sage_object.pxd index 93709c67d6d..419cec95c70 100644 --- a/src/sage/structure/sage_object.pxd +++ b/src/sage/structure/sage_object.pxd @@ -1,3 +1,74 @@ +from libc.stdint cimport uint32_t +from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE + + cdef class SageObject: pass + +cdef inline bint rich_to_bool(int op, int c): + """ + Return the corresponding ``True`` or ``False`` value for a rich + comparison, given the result of an ordinary comparison. + + INPUT: + + - ``op`` -- a rich comparison operation (e.g. ``Py_EQ``) + + - ``c`` -- the result of an ordinary comparison: -1, 0 or 1. + + OUTPUT: 1 or 0 (corresponding to ``True`` and ``False``) + + .. SEEALSO:: + + ``rich_to_bool_sgn`` if ``c`` could be outside the [-1, 1] + range. + + EXAMPLES:: + + sage: 0 < 5, 5 < 5, 5 < -8 + (True, False, False) + sage: 0 <= 5, 5 <= 5, 5 <= -8 + (True, True, False) + sage: 0 >= 5, 5 >= 5, 5 >= -8 + (False, True, True) + sage: 0 > 5, 5 > 5, 5 > -8 + (False, False, True) + sage: 0 == 5, 5 == 5, 5 == -8 + (False, True, False) + sage: 0 != 5, 5 != 5, 5 != -8 + (True, False, True) + """ + # op is a value in [0,5], c a value in [-1,1]. We implement this + # function very efficienly using a bitfield. Note that the masking + # below implies we consider c mod 4, so c = -1 implicitly becomes + # c = 3. + + # The 4 lines below involve just constants, so the compiler should + # optimize them to just one constant value for "bits". + cdef uint32_t less_bits = (1 << Py_LT) + (1 << Py_LE) + (1 << Py_NE) + cdef uint32_t equal_bits = (1 << Py_LE) + (1 << Py_GE) + (1 << Py_EQ) + cdef uint32_t greater_bits = (1 << Py_GT) + (1 << Py_GE) + (1 << Py_NE) + cdef uint32_t bits = (less_bits << 24) + (equal_bits) + (greater_bits << 8) + + cdef int shift = 8*c + op + + # The shift masking (shift & 31) will likely be optimized away by + # the compiler since shift and bit test instructions implicitly + # mask their offset. + return (bits >> (shift & 31)) & 1 + + +cdef inline bint rich_to_bool_sgn(int op, long c): + """ + Same as ``rich_to_bool``, but allow any `c < 0` and `c > 0` + instead of only `-1` and `1`. + + .. NOTE:: + + This is in particular needed for ``mpz_cmp()``. + """ + if c < 0: + return rich_to_bool(op, -1) + else: + return rich_to_bool(op, c != 0) From 2201c9cedee5a935dae2c24fdc54a5aa09201bda Mon Sep 17 00:00:00 2001 From: Leif Leonhardy Date: Sun, 26 Apr 2015 03:43:30 +0200 Subject: [PATCH 555/665] Add patch to let ncurses build with GCC 5.x (changed output of 'cpp') See top of the patch for further explanation. --- ...around_changed_output_of_GNU_cpp_5.x.patch | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 build/pkgs/ncurses/patches/work_around_changed_output_of_GNU_cpp_5.x.patch diff --git a/build/pkgs/ncurses/patches/work_around_changed_output_of_GNU_cpp_5.x.patch b/build/pkgs/ncurses/patches/work_around_changed_output_of_GNU_cpp_5.x.patch new file mode 100644 index 00000000000..af82739cfbb --- /dev/null +++ b/build/pkgs/ncurses/patches/work_around_changed_output_of_GNU_cpp_5.x.patch @@ -0,0 +1,30 @@ +Building ncurses with GCC 5.1 (or more precisely, with its 'cpp') fails with +a syntax error, caused by earlier preprocessing. + +(I'm not entirely sure whether it's a GCC bug or rather caused by a new +feature which breaks further processing with 'awk' and 'sed'; I *think* +at least the 'awk' inline script "AW2" simply isn't prepared for the changed +output of 'cpp' w.r.t. line directives [1]. Anyway, the patch fixes the issue.) + +[1] https://gcc.gnu.org/gcc-5/porting_to.html + + +--- ncurses-5.9.20131221/ncurses/base/MKlib_gen.sh 2011-06-04 21:14:08.000000000 +0200 ++++ ncurses-5.9.20131221/ncurses/base/MKlib_gen.sh 2015-04-26 00:47:06.911680782 +0200 +@@ -62,7 +62,15 @@ + if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + if test "${LC_COLLATE+set}" = set; then LC_COLLATE=C; export LC_COLLATE; fi + +-preprocessor="$1 -DNCURSES_INTERNALS -I../include" ++# Work around "unexpected" output of GCC 5.1.0's cpp w.r.t. #line directives ++# by simply suppressing them: ++case `$1 -dumpversion 2>/dev/null` in ++ 5.[01].*) # assume a "broken" one ++ preprocessor="$1 -P -DNCURSES_INTERNALS -I../include" ++ ;; ++ *) ++ preprocessor="$1 -DNCURSES_INTERNALS -I../include" ++esac + AWK="$2" + USE="$3" + From 3c5cd0f74446992a2b98f84c34043cfa181b68b4 Mon Sep 17 00:00:00 2001 From: Buck Evan Date: Sat, 25 Apr 2015 21:06:50 -0700 Subject: [PATCH 556/665] skip R-aqua on osx 10.10. see #18254 --- build/pkgs/r/spkg-install | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/pkgs/r/spkg-install b/build/pkgs/r/spkg-install index 2bb904de821..06a340dd0b9 100755 --- a/build/pkgs/r/spkg-install +++ b/build/pkgs/r/spkg-install @@ -84,6 +84,13 @@ if [ "$UNAME" = "Darwin" ]; then R_CONFIGURE="--enable-R-framework=no $R_CONFIGURE" fi +# OS X 10.10 and/or Xcode 6.3 broke the R installation. See +# http://trac.sagemath.org/ticket/18254. +if { uname -sr | grep 'Darwin 14\.' ;} &>/dev/null; then + echo "OS X 10.10: Configuring R without aqua support." + R_CONFIGURE="--with-aqua=no $R_CONFIGURE" +fi + if [ "$UNAME" = "CYGWIN" ]; then # Cygwin libm does not provide "long double" functions # and we do not install Cephes on Cygwin at the moment From 5856c64018eeb56840aaad2c117af4e849b009d1 Mon Sep 17 00:00:00 2001 From: Daniel Bump Date: Sun, 26 Apr 2015 06:42:55 -0700 Subject: [PATCH 557/665] lazy_import --- src/sage/combinat/root_system/all.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 763ea787cfe..98befe7accb 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -14,4 +14,5 @@ from weyl_characters import WeylCharacterRing, WeightRing from branching_rules import BranchingRule, branching_rule_from_plethysm, branching_rule lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials') -from integrable_representations import IntegrableRepresentation +lazy_import('sage.combinat.root_system.integrable_representations', 'IntegrableRepresentation') + From 110c8fa7f74010a01187f1413e2e693868cf1a66 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 26 Apr 2015 19:44:41 +0200 Subject: [PATCH 558/665] trac #18045: Review --- src/sage/graphs/generic_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 79d9d1c2cad..001dacc2f12 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4043,7 +4043,7 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal attribute if minimal is set to ``False``. - The value ``True``, in order to indicate that the embedding stored - as ``_embedding`` should be used (see eg's). + as ``_embedding`` should be used (see examples). - ``minimal (boolean)`` - whether or not to compute the minimal genus of the graph (i.e., testing all embeddings). If From 764ad4e2462639dfb2a6d105004d9b19cf907e26 Mon Sep 17 00:00:00 2001 From: Leif Leonhardy Date: Sun, 26 Apr 2015 21:13:41 +0200 Subject: [PATCH 559/665] Add patch fixing MPIR (2.7.0.alpha12) 'configure' failure with GCC 5.x (#18247) Reduced patch (only patching acinclude.m4) submitted upstream. --- .../patches/fix_configure_with_GCC_5.x.patch | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 build/pkgs/mpir/patches/fix_configure_with_GCC_5.x.patch diff --git a/build/pkgs/mpir/patches/fix_configure_with_GCC_5.x.patch b/build/pkgs/mpir/patches/fix_configure_with_GCC_5.x.patch new file mode 100644 index 00000000000..c62c6af796e --- /dev/null +++ b/build/pkgs/mpir/patches/fix_configure_with_GCC_5.x.patch @@ -0,0 +1,37 @@ +Fix 'configure' test that fails with GCC 5.x just because it now defaults +to standard C inline semantics. (See Sage trac #18247.) + +--- mpir-2.7.0/acinclude.m4 2014-09-14 21:59:12.000000000 +0200 ++++ mpir-2.7.0/acinclude.m4 2015-04-26 19:49:14.603554112 +0200 +@@ -584,6 +584,9 @@ + + #if defined(__GNUC__) && !defined(__clang__) + typedef unsigned long long t1;typedef t1*t2; ++#if defined(__GNUC_STDC_INLINE__) /* e.g. GCC 5.x defaults to this, not __GNUC_GNU_INLINE__ */ ++extern ++#endif + __inline__ t1 e(t2 rp,t2 up,int n,t1 v0) + {t1 c,x,r;int i;if(v0){c=1;for(i=1;i Date: Sun, 26 Apr 2015 22:02:21 +0200 Subject: [PATCH 560/665] trac #18XXX clean-up of hyperbolic plane geodesics --- .../hyperbolic_space/hyperbolic_geodesic.py | 152 +++++++++--------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index dfd2c548b64..73fd2c6414e 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -48,11 +48,13 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.rings.infinity import infinity from sage.rings.all import CC, RR +from sage.plot.arc import arc +from sage.plot.line import line from sage.symbolic.constants import pi from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from sage.functions.other import real, imag, sqrt -from sage.functions.trig import sin, cos, arccos +from sage.functions.trig import arccos from sage.functions.log import exp from sage.functions.hyperbolic import sinh, cosh, arcsinh from sage.symbolic.ring import SR @@ -144,7 +146,7 @@ def _complete(self): """ if self._model.is_bounded(): return (self._start.is_boundary() and self._end.is_boundary()) - return False #All non-bounded geodesics start life incomplete. + return False # All non-bounded geodesics start life incomplete. def _repr_(self): r""" @@ -164,8 +166,10 @@ def _repr_(self): sage: HyperbolicPlane().HM().get_geodesic((0,0,1), (0, 1, sqrt(Integer(2)))) Geodesic in HM from (0, 0, 1) to (0, 1, sqrt(2)) """ - return "Geodesic in {0} from {1} to {2}".format(self._model.short_name(), - self._start.coordinates(), self._end.coordinates()) + msg = "Geodesic in {0} from {1} to {2}" + return msg.format(self._model.short_name(), + self._start.coordinates(), + self._end.coordinates()) def __eq__(self, other): r""" @@ -365,7 +369,7 @@ def is_asymptotically_parallel(self, other): """ p1, p2 = self.complete().endpoints() q1, q2 = other.complete().endpoints() - return ((self != other) and ((p1 in [q1, q2]) or (p2 in [q1,q2])) + return ((self != other) and ((p1 in [q1, q2]) or (p2 in [q1, q2])) and self.model() is other.model()) def is_ultra_parallel(self, other): @@ -732,6 +736,7 @@ def length(self): ##################################################################### ## UHP geodesics + class HyperbolicGeodesicUHP(HyperbolicGeodesic): r""" Create a geodesic in the upper half plane model. @@ -769,11 +774,11 @@ def reflection_involution(self): """ x, y = [real(k.coordinates()) for k in self.ideal_endpoints()] if x == infinity: - M = matrix([[1,-2*y],[0,-1]]) + M = matrix([[1, -2*y], [0, -1]]) elif y == infinity: - M = matrix([[1,-2*x],[0,-1]]) + M = matrix([[1, -2*x], [0, -1]]) else: - M = matrix([[(x+y)/(y-x),- 2*x*y/(y-x)], [2/(y-x), -(x+y)/(y-x)]]) + M = matrix([[(x+y)/(y-x), -2*x*y/(y-x)], [2/(y-x), -(x+y)/(y-x)]]) return self._model.get_isometry(M) def show(self, boundary=True, **options): @@ -782,7 +787,10 @@ def show(self, boundary=True, **options): EXAMPLES:: - sage: HyperbolicPlane().UHP().get_geodesic(0, 1).show() + sage: UHP = HyperbolicPlane().UHP() + sage: UHP.get_geodesic(0, 1).show() + Graphics object consisting of 2 graphics primitives + sage: UHP.get_geodesic(I, 3+4*I).show(linestyle="dashed", color="red") Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} @@ -791,7 +799,7 @@ def show(self, boundary=True, **options): end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] if (abs(real(end_1) - real(end_2)) < EPSILON) \ - or CC(infinity) in [end_1, end_2]: #on same vertical line + or CC(infinity) in [end_1, end_2]: # on same vertical line # If one of the endpoints is infinity, we replace it with a # large finite point if end_1 == CC(infinity): @@ -800,7 +808,6 @@ def show(self, boundary=True, **options): elif end_2 == CC(infinity): end_2 = (real(end_1), (imag(end_1) + 10)) end_1 = (real(end_1), imag(end_1)) - from sage.plot.line import line pic = line((end_1, end_2), **opts) if boundary: cent = min(bd_1, bd_2) @@ -809,18 +816,14 @@ def show(self, boundary=True, **options): pic = bd_pic + pic return pic else: - center = (bd_1 + bd_2)/2 # Circle center - radius = abs(bd_1 - bd_2)/2 + center = (bd_1 + bd_2) / 2 # Circle center + radius = abs(bd_1 - bd_2) / 2 theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if abs(theta1 - theta2) < EPSILON: theta2 += pi - [theta1, theta2] = sorted([theta1, theta2]) - from sage.plot.plot import parametric_plot - x = SR.var('x') - pic = parametric_plot((radius*cos(x) + real(center), - radius*sin(x) + imag(center)), - (x, theta1, theta2), **opts) + pic = arc((real(center), imag(center)), radius, + sector=(theta1, theta2), **opts) if boundary: # We want to draw a segment of the real line. The # computations below compute the projection of the @@ -957,7 +960,7 @@ def intersection(self, other): """ start_1, end_1 = sorted(self.ideal_endpoints(), key=str) start_2, end_2 = sorted(other.ideal_endpoints(), key=str) - if start_1 == start_2 and end_1 == end_2: # Unoriented geods are same + if start_1 == start_2 and end_1 == end_2: # Unoriented geods are same return [start_1, end_1] if start_1 == start_2: return start_1 @@ -970,7 +973,7 @@ def intersection(self, other): return [] return C.fixed_point_set() - def perpendicular_bisector(self): #UHP + def perpendicular_bisector(self): # UHP r""" Return the perpendicular bisector of the hyperbolic geodesic ``self`` if that geodesic has finite length. @@ -999,9 +1002,12 @@ def perpendicular_bisector(self): #UHP T1 = matrix([[exp(d/2), 0], [0, exp(-d/2)]]) s2 = sqrt(2) * 0.5 T2 = matrix([[s2, -s2], [s2, s2]]) - isom_mtrx = S.inverse() * (T1 * T2) * S # We need to clean this matrix up. - if (isom_mtrx - isom_mtrx.conjugate()).norm() < 5*EPSILON: # Imaginary part is small. - isom_mtrx = (isom_mtrx + isom_mtrx.conjugate()) / 2 # Set it to its real part. + isom_mtrx = S.inverse() * (T1 * T2) * S + # We need to clean this matrix up. + if (isom_mtrx - isom_mtrx.conjugate()).norm() < 5 * EPSILON: + # Imaginary part is small. + isom_mtrx = (isom_mtrx + isom_mtrx.conjugate()) / 2 + # Set it to its real part. H = self._model.get_isometry(isom_mtrx) return self._model.get_geodesic(H(self._start), H(self._end)) @@ -1043,7 +1049,7 @@ def midpoint(self): # UHP end_p = end return self._model.get_point(mobius_transform(M, end_p)) - def angle(self, other): #UHP + def angle(self, other): # UHP r""" Return the angle between any two given completed geodesics if they intersect. @@ -1102,13 +1108,13 @@ def angle(self, other): #UHP if (abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON): return 0 - elif p2 != infinity: # geodesic not a straight line + elif p2 != infinity: # geodesic not a straight line # So we send it to the geodesic with endpoints [0, oo] - T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1+p2)/2, p2) + T = HyperbolicGeodesicUHP._crossratio_matrix(p1, (p1 + p2) / 2, p2) else: # geodesic is a straight line, so we send it to the geodesic # with endpoints [0,oo] - T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1+1, p2) + T = HyperbolicGeodesicUHP._crossratio_matrix(p1, p1 + 1, p2) # b1 and b2 are the endpoints of the image of other b1, b2 = [mobius_transform(T, k) for k in [q1, q2]] # If other is now a straight line... @@ -1151,12 +1157,14 @@ def _to_std_geod(self, p): # outmat below will be returned after we normalize the determinant. outmat = B * HyperbolicGeodesicUHP._crossratio_matrix(s, p, e) outmat = outmat / outmat.det().sqrt() - if (outmat - outmat.conjugate()).norm(1) < 10**-9: # Small imaginary part. - outmat = (outmat + outmat.conjugate()) / 2 # Set it equal to its real part. + if (outmat - outmat.conjugate()).norm(1) < 10**-9: + # Small imaginary part. + outmat = (outmat + outmat.conjugate()) / 2 + # Set it equal to its real part. return outmat @staticmethod - def _crossratio_matrix(p0, p1, p2): #UHP + def _crossratio_matrix(p0, p1, p2): # UHP r""" Given three points (the list `p`) in `\mathbb{CP}^{1}` in affine coordinates, return the linear fractional transformation taking @@ -1201,6 +1209,7 @@ def _crossratio_matrix(p0, p1, p2): #UHP ##################################################################### ## Other geodesics + class HyperbolicGeodesicPD(HyperbolicGeodesic): r""" A geodesic in the Poincaré disk model. @@ -1223,52 +1232,52 @@ def show(self, boundary=True, **options): r""" Plot ``self``. - EXAMPLES:: + EXAMPLES: + + First some lines:: + + sage: PD = HyperbolicPlane().PD() + sage: PD.get_geodesic(0, 1).show() + Graphics object consisting of 2 graphics primitives + sage: PD.get_geodesic(0, 0.3+0.8*I).show() + Graphics object consisting of 2 graphics primitives + + Then some generic geodesics:: - sage: HyperbolicPlane().PD().get_geodesic(0, 1).show() + sage: PD.get_geodesic(-0.5, 0.3+0.4*I).show() + Graphics object consisting of 2 graphics primitives + sage: PD.get_geodesic(-1, exp(3*I*pi/7)).show(linestyle="dashed", color="red") + Graphics object consisting of 2 graphics primitives + sage: PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)).show(thickness=6, color="orange") Graphics object consisting of 2 graphics primitives """ - opts = dict([('axes', False), ('aspect_ratio', 1)]) + opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] # Check to see if it's a line - if bool(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))**2 < EPSILON: - from sage.plot.line import line - pic = line([(real(bd_1),imag(bd_1)),(real(bd_2),imag(bd_2))], - **opts) + if abs(bd_1 + bd_2) < EPSILON: + pic = line([end_1, end_2], **opts) else: # If we are here, we know it's not a line # So we compute the center and radius of the circle - center = (1/(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) * - ((imag(bd_2)-imag(bd_1)) + (real(bd_1)-real(bd_2))*I)) - radius = RR(abs(bd_1 - center)) # abs is Euclidean distance - # Now we calculate the angles for the parametric plot + invdet = RR.one() / (real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) + centerx = (imag(bd_2) - imag(bd_1)) * invdet + centery = (real(bd_1) - real(bd_2)) * invdet + center = centerx + I * centery + radius = RR(abs(bd_1 - center)) + # Now we calculate the angles for the arc theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() - if theta2 < theta1: - theta1, theta2 = theta2, theta1 - from sage.plot.plot import parametric_plot - x = SR.var('x') - mid = (theta1 + theta2)/2.0 - if (radius*cos(mid) + real(center))**2 + \ - (radius*sin(mid) + imag(center))**2 > 1.0: - # Swap theta1 and theta2 - tmp = theta1 + 2*pi - theta1 = theta2 - theta2 = tmp - pic = parametric_plot((radius*cos(x) + real(center), - radius*sin(x) + imag(center)), - (x, theta1, theta2), **opts) - - else: - pic = parametric_plot((radius*cos(x) + real(center), - radius*sin(x) + imag(center)), - (x, theta1, theta2), **opts) + theta1, theta2 = sorted([theta1, theta2]) + # Make sure the sector is inside the disk + if theta2 - theta1 > pi: + theta1 += 2 * pi + pic = arc((centerx, centery), radius, + sector=(theta1, theta2), **opts) if boundary: - bd_pic = self._model.get_background_graphic() - pic = bd_pic + pic + pic += self._model.get_background_graphic() return pic @@ -1299,13 +1308,11 @@ def show(self, boundary=True, **options): sage: HyperbolicPlane().KM().get_geodesic((0,0), (1,0)).show() Graphics object consisting of 2 graphics primitives """ - from sage.plot.line import line opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) pic = line([k.coordinates() for k in self.endpoints()], **opts) if boundary: - bd_pic = self._model.get_background_graphic() - pic = bd_pic + pic + pic += self._model.get_background_graphic() return pic @@ -1340,20 +1347,18 @@ def show(self, show_hyperboloid=True, **graphics_options): Graphics3d Object """ x = SR.var('x') - y = SR.var('y') - z = SR.var('z') opts = self.graphics_options() opts.update(graphics_options) - v1,u2 = [vector(k.coordinates()) for k in self.endpoints()] + v1, u2 = [vector(k.coordinates()) for k in self.endpoints()] # Lorentzian Gram Shmidt. The original vectors will be # u1, u2 and the orthogonal ones will be v1, v2. Except # v1 = u1, and I don't want to declare another variable, # hence the odd naming convention above. # We need the Lorentz dot product of v1 and u2. v1_ldot_u2 = u2[0]*v1[0] + u2[1]*v1[1] - u2[2]*v1[2] - v2 = u2 + v1_ldot_u2*v1 + v2 = u2 + v1_ldot_u2 * v1 v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2) - v2 = v2/v2_norm + v2 = v2 / v2_norm v2_ldot_u2 = u2[0]*v2[0] + u2[1]*v2[1] - u2[2]*v2[2] # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1 # That is, v1 is unit timelike and v2 is unit spacelike. @@ -1361,8 +1366,7 @@ def show(self, show_hyperboloid=True, **graphics_options): hyperbola = cosh(x)*v1 + sinh(x)*v2 endtime = arcsinh(v2_ldot_u2) from sage.plot.plot3d.all import parametric_plot3d - pic = parametric_plot3d(hyperbola,(x,0, endtime), **graphics_options) + pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options) if show_hyperboloid: - bd_pic = self._model.get_background_graphic() - pic = bd_pic + pic + pic += self._model.get_background_graphic() return pic From 313a400146b0fb19d80c31117d44ce735041d4ec Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sun, 26 Apr 2015 22:49:09 +0200 Subject: [PATCH 561/665] Optimize rich_to_bool_sgn --- src/sage/rings/integer.pyx | 8 +++----- src/sage/structure/sage_object.pxd | 7 ++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 27904a3f798..d534ebe372d 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -894,11 +894,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return rich_to_bool_sgn(op, c) cpdef int _cmp_(left, sage.structure.element.Element right) except -2: - cdef int i - i = mpz_cmp((left).value, (right).value) - if i < 0: return -1 - elif i == 0: return 0 - else: return 1 + cdef int c + c = mpz_cmp((left).value, (right).value) + return (c > 0) - (c < 0) def __copy__(self): """ diff --git a/src/sage/structure/sage_object.pxd b/src/sage/structure/sage_object.pxd index 419cec95c70..ac613d0dda4 100644 --- a/src/sage/structure/sage_object.pxd +++ b/src/sage/structure/sage_object.pxd @@ -59,7 +59,7 @@ cdef inline bint rich_to_bool(int op, int c): return (bits >> (shift & 31)) & 1 -cdef inline bint rich_to_bool_sgn(int op, long c): +cdef inline bint rich_to_bool_sgn(int op, int c): """ Same as ``rich_to_bool``, but allow any `c < 0` and `c > 0` instead of only `-1` and `1`. @@ -68,7 +68,4 @@ cdef inline bint rich_to_bool_sgn(int op, long c): This is in particular needed for ``mpz_cmp()``. """ - if c < 0: - return rich_to_bool(op, -1) - else: - return rich_to_bool(op, c != 0) + return rich_to_bool(op, (c > 0) - (c < 0)) From 9701c1aa4b8ba110229da182fa6352c827b6168b Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 26 Apr 2015 18:43:24 -0400 Subject: [PATCH 562/665] Fixed truncated docstring Other minor documentation infelicities also fixed. --- src/sage/combinat/tableau.py | 47 ++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 3350c8821ae..0d864039cc8 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -327,7 +327,7 @@ def __init__(self, parent, t): ClonableList.__init__(self, parent, t) # This dispatches the input verification to the :meth:`check` # method. - + def __eq__(self, other): r""" Check whether ``self`` is equal to ``other``. @@ -364,7 +364,7 @@ def __eq__(self, other): return list(self) == list(other) else: return list(self) == other - + def __ne__(self, other): r""" Check whether ``self`` is unequal to ``other``. @@ -1717,7 +1717,7 @@ def k_weight(self, k): REFERENCES: .. [Ive2012] S. Iveson, - *Tableaux on `k + 1`-cores, reduced words for affine + *Tableaux on `k + 1`-cores, reduced words for affine permutations, and `k`-Schur expansions*, Operators on `k`-tableaux and the `k`-Littlewood-Richardson rule for a special case, @@ -5164,18 +5164,29 @@ def __contains__(self, x): and max(max(row) for row in x) <= self.max_entry) def random_element(self): - """ - Generate a random ``SemistandardTableau`` with uniform probability. + r""" + Generate a random :class:`SemistandardTableau` with uniform probability. The RSK algorithm gives a bijection between symmetric `k\times k` matrices of nonnegative integers that sum to `n` and semistandard tableaux with size `n` and maximum entry `k`. - To generate a random symmetric matrix with a given sum, we first choose the trace of the - matrix + The number of `k\times k` symmetric matrices of nonnegative integers + having sum of elements on the diagonal `i` and sum of elements above + the diagonal `j` is `\binom{k + i - 1}{k - 1}\binom{\binom{k}{2} + j - 1}{\binom{k}{2} - 1}`. + We first choose the sum of the elements on the diagonal randomly weighted by the + number of matrices having that trace. We then create random integer vectors + of length `k` having that sum and use them to generate a `k\times k` diagonal matrix. + Then we take a random integer vector of length `\binom{k}{2}` summing to half the + remainder and distribute it symmetrically to the remainder of the matrix. - TESTS:: + Applying RSK to the random symmetric matrix gives us a pair of identical + :class:`SemistandardTableau` of which we choose the first. + + EXAMPLES:: + sage: SemistandardTableaux(6).random_element() + [[2, 2], [3, 3], [6, 6]] sage: SemistandardTableaux(6, max_entry=7).random_element() [[2, 2], [3, 3], [6, 6]] @@ -5191,7 +5202,7 @@ def random_element(self): randpos = ZZ.random_element(sum(weights)) tot = weights[0] pos = 0 - while (randpos >= tot): + while randpos >= tot: pos += 1 tot += weights[pos] # we now have pos elements over the diagonal and n - 2 * pos on it @@ -5204,7 +5215,7 @@ def random_element(self): m[j,i] = above_diagonal[index] index += 1 return RSK(m)[0] - + def cardinality(self): """ Return the cardinality of ``self``. @@ -5392,16 +5403,18 @@ def _repr_(self): def random_element(self): """ - Returns a uniformly distributed random tableau of the given shape and max_entry. + Return a uniformly distributed random tableau of the given ``shape`` and ``max_entry``. - Uses the algorithm from [Krat99] based on the Novelli-Pak-Stoyanovskii bijection + Uses the algorithm from [Krat99]_ based on the Novelli-Pak-Stoyanovskii bijection - TESTS:: + EXAMPLES:: + sage: SemistandardTableaux([2, 2, 1, 1]).random_element() + [[1, 1], [2, 3], [3], [5]] sage: SemistandardTableaux([2, 2, 1, 1], max_entry=7).random_element() - [[1, 2], [2, 4], [3], [5]] + [[1, 4], [5, 5], [6], [7]] + - REFERENCES: .. [Krat99] C. Krattenthaler, @@ -6007,7 +6020,7 @@ def random_element(self): EXAMPLES:: sage: StandardTableaux(5).random_element() # random - [[1, 4, 5], [2], [3]] + [[1, 4, 5], [2], [3]] sage: StandardTableaux(0).random_element() [] sage: StandardTableaux(1).random_element() @@ -6468,5 +6481,3 @@ def __setstate__(self, state): register_unpickle_override('sage.combinat.tableau', 'SemistandardTableaux_p', SemistandardTableaux_shape) register_unpickle_override('sage.combinat.tableau', 'SemistandardTableaux_nmu', SemistandardTableaux_size_weight) register_unpickle_override('sage.combinat.tableau', 'SemistandardTableaux_pmu', SemistandardTableaux_shape_weight) - - From b088789862e9c044e4cc6a6130a1bf4351f7f281 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 26 Apr 2015 19:25:32 -0400 Subject: [PATCH 563/665] fix SPKG.txt title --- build/pkgs/threejs/SPKG.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/threejs/SPKG.txt b/build/pkgs/threejs/SPKG.txt index 37bdee51f52..31d2fc42118 100644 --- a/build/pkgs/threejs/SPKG.txt +++ b/build/pkgs/threejs/SPKG.txt @@ -1,4 +1,4 @@ -= MathJax = += Three.js = == Description == From cc64f713e772abc5cd10916abba548bb3149f1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Apr 2015 09:11:18 +0200 Subject: [PATCH 564/665] trac #18307 a doc typo in arc.py --- src/sage/plot/arc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index c11e83c16af..04fac945f42 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -51,7 +51,7 @@ def __init__(self, x, y, r1, r2, angle, s1, s2, options): """ Initializes base class ``Arc``. - EXAMPLES: + EXAMPLES:: sage: A = arc((2,3),1,1,pi/4,(0,pi)) sage: A[0].x == 2 From 23dd71c648aa34a1e563a1d59133f238f9575597 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 10:38:54 +0200 Subject: [PATCH 565/665] Simplified _repr_ and _latex_ methods using a new helper function --- src/sage/coding/channel_constructions.py | 85 ++++++++++++------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 7ad27802dd2..c698d6c7d43 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -70,6 +70,37 @@ def random_error_vector(n, F, error_positions): vect[i] = F._random_nonzero_element() return vector(F, vect) +def format_interval(t): + r""" + Returns a formatted string representation of ``t``. + + This method should be called by any representation function in Channel classes. + + .. NOTE:: + + This is a helper function, which should only be used when implementing new channels. + + INPUT: + + - ``t`` -- a list or a tuple + + OUTPUT: + + - a string + + TESTS:: + + sage: t = (5, 5) + sage: sage.coding.channel_constructions.format_interval(t) + '5' + + sage: t = (2, 10) + sage: sage.coding.channel_constructions.format_interval(t) + 'between 2 and 10' + + """ + return str(t[0]) if t[0] == t[1] else 'between %s and %s' % (t[0], t[1]) + class Channel(SageObject): r""" Abstract top-class for Channel objects. @@ -269,7 +300,7 @@ class StaticErrorRateChannel(Channel): sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan - Static error rate channel creating 2 error(s) + Static error rate channel creating 2 errors We can also pass a tuple for the number of errors:: @@ -313,15 +344,11 @@ def _repr_(self): sage: n_err = 42 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: Chan - Static error rate channel creating 42 error(s) + Static error rate channel creating 42 errors """ no_err = self.number_errors() - if no_err[0] == no_err[1]: - return "Static error rate channel creating %s error(s)"\ - % no_err[0] - else: - return "Static error rate channel creating between %s and %s errors"\ - % (no_err[0], no_err[1]) + return "Static error rate channel creating %s errors"\ + % (format_interval(no_err)) def _latex_(self): r""" @@ -336,12 +363,8 @@ def _latex_(self): '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' """ no_err = self.number_errors() - if no_err[0] == no_err[1]: - return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ - % no_err[0] - else: - return "\\textnormal{Static error rate channel, creating between %s and %s errors}"\ - % (no_err[0], no_err[1]) + return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ + % format_interval(no_err) def transmit_unsafe(self, message): r""" @@ -445,7 +468,7 @@ class ErrorErasureChannel(Channel): sage: n_err, n_era = 2, 2 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: Chan - Error-and-erasure channel creating 2 error(s) and 2 erasure(s) + Error-and-erasure channel creating 2 errors and 2 erasures We can also pass the number of errors and erasures as a couple of integers:: @@ -500,22 +523,12 @@ def _repr_(self): sage: n_err, n_era = 21, 21 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: Chan - Error-and-erasure channel creating 21 error(s) and 21 erasure(s) + Error-and-erasure channel creating 21 errors and 21 erasures """ no_err = self.number_errors() no_era = self.number_erasures() - if no_err[0] == no_err[1] and no_era[0] == no_era[1]: - return "Error-and-erasure channel creating %s error(s) and %s erasure(s)"\ - %(no_err[0], no_era[0]) - elif no_err[0] != no_err[1] and no_era[0] == no_era[1]: - return "Error-and-erasure channel creating between %s and %s errors and %s erasure(s)"\ - % (no_err[0], no_err[1], no_era[0]) - elif no_err[0] == no_err[1] and no_era[0] != no_era[1]: - return "Error-and-erasure channel creating %s error(s) and between %s and %s erasures"\ - % (no_err[0], no_era[0], no_era[1]) - else: - return "Error-and-erasure channel creating between %s and %s errors and between %s and %s erasures"\ - % (no_err[0], no_err[1], no_era[0], no_era[1]) + return "Error-and-erasure channel creating %s errors and %s erasures"\ + % (format_interval(no_err), format_interval(no_era)) def _latex_(self): r""" @@ -527,22 +540,12 @@ def _latex_(self): sage: n_err, n_era = 21, 21 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: latex(Chan) - \textnormal{Error-and-erasure channel creating 21 error(s) and 21 erasure(s)} + \textnormal{Error-and-erasure channel creating 21 errors and 21 erasures} """ no_err = self.number_errors() no_era = self.number_erasures() - if no_err[0] == no_err[1] and no_era[0] == no_era[1]: - return "\\textnormal{Error-and-erasure channel creating %s error(s) and %s erasure(s)}"\ - %(no_err[0], no_era[0]) - elif no_err[0] != no_err[1] and no_era[0] == no_era[1]: - return "\\textnormal{Error-and-erasure channel creating between %s and %s error(s) and %s erasure(s)}"\ - % (no_err[0], no_err[1], no_era[0]) - elif no_err[0] == no_err[1] and no_era[0] != no_era[1]: - return "\\textnormal{Error-and-erasure channel creating %s error(s) and between %s and %s erasure(s)}"\ - % (no_err[0], no_era[0], no_era[1]) - else: - return "\\textnormal{Error-and-erasure channel creating between %s and %s error(s) and between %s and %s erasure(s)}"\ - % (no_err[0], no_err[1], no_era[0], no_era[1]) + return "\\textnormal{Error-and-erasure channel creating %s errors and %s erasures}"\ + % (format_interval(no_err), format_interval(no_era)) def transmit_unsafe(self, message): r""" From cb7b137f3954c5f62968f332550d63c60263f2b6 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 10:53:51 +0200 Subject: [PATCH 566/665] Some changes to the documentation --- src/sage/coding/channel_constructions.py | 72 ++++++++++-------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index c698d6c7d43..4b13603ddab 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -166,6 +166,7 @@ def transmit(self, message): r""" Returns ``message``, modified accordingly with the algorithm of the channel it was transmitted through. + Checks if ``message`` belongs to the input space, and returns an exception if not. INPUT: @@ -178,7 +179,7 @@ def transmit(self, message): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) + sage: F = GF(59)^6 sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) @@ -188,9 +189,8 @@ def transmit(self, message): If we transmit a vector which is not in the input space of ``self``:: - sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^6, n_err) sage: msg = (4, 8, 15, 16, 23, 42) sage: Chan.transmit(msg) Traceback (most recent call last): @@ -215,9 +215,8 @@ def input_space(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^6, n_err) sage: Chan.input_space() Vector space of dimension 6 over Finite Field of size 59 @@ -230,9 +229,8 @@ def output_space(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) sage: n_err = 2 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^6, n_err) sage: Chan.output_space() Vector space of dimension 6 over Finite Field of size 59 """ @@ -243,6 +241,7 @@ def transmit_unsafe(self, message): r""" Returns ``message``, modified accordingly with the algorithm of the channel it was transmitted through. + This method does not check if ``message`` belongs to the input space of``self``. This is an abstract method which should be reimplemented in all the subclasses of @@ -260,9 +259,9 @@ def transmit_unsafe(self, message): class StaticErrorRateChannel(Channel): r""" - Constructs a channel which adds a static number of errors to each message - it transmits. The input space and the output space of this channel - are the same. + Channel which adds a static number of errors to each message it transmits. + + The input space and the output space of this channel are the same. The main purpose of communication channels is to transmit messages, which can be achieved with two methods: @@ -296,17 +295,15 @@ class StaticErrorRateChannel(Channel): We construct a StaticErrorRateChannel which adds 2 errors to any transmitted message:: - sage: F = VectorSpace(GF(59), 40) sage: n_err = 2 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^40, n_err) sage: Chan Static error rate channel creating 2 errors We can also pass a tuple for the number of errors:: - sage: F = VectorSpace(GF(59), 40) sage: n_err = (1, 10) - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^40, n_err) sage: Chan Static error rate channel creating between 1 and 10 errors """ @@ -318,9 +315,8 @@ def __init__(self, space, number_errors): If the number of errors exceeds the dimension of the input space, it will return an error:: - sage: F = VectorSpace(GF(59), 40) sage: n_err = 42 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^40, n_err) Traceback (most recent call last): ... ValueError: There might be more errors than the dimension of the input space @@ -340,9 +336,8 @@ def _repr_(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^50, n_err) sage: Chan Static error rate channel creating 42 errors """ @@ -356,9 +351,8 @@ def _latex_(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 50) sage: n_err = 42 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^50, n_err) sage: Chan._latex_() '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' """ @@ -369,8 +363,10 @@ def _latex_(self): def transmit_unsafe(self, message): r""" Returns ``message`` with as many errors as ``self._number_errors`` in it. + If ``self._number_errors`` was passed as a tuple for the number of errors, it will pick a random integer between the bounds of the tuple and use it as the number of errors. + This method does not check if ``message`` belongs to the input space of``self``. INPUT: @@ -383,7 +379,7 @@ def transmit_unsafe(self, message): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) + sage: F = GF(59)^6 sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(F, n_err) sage: msg = F((4, 8, 15, 16, 23, 42)) @@ -404,9 +400,8 @@ def number_errors(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) sage: n_err = 3 - sage: Chan = channels.StaticErrorRateChannel(F, n_err) + sage: Chan = channels.StaticErrorRateChannel(GF(59)^6, n_err) sage: Chan.number_errors() (3, 3) """ @@ -423,8 +418,9 @@ def number_errors(self): class ErrorErasureChannel(Channel): r""" - Constructs a channel which adds errors to any message it transmits. It also erases several positions - in the transmitted message. The output space of this channel is a cartesian product + Channel which adds errors and erases several positions in any message it transmits. + + The output space of this channel is a cartesian product between its input space and a VectorSpace of the same dimension over GF(2) The main purpose of communication channels is to transmit messages, which can be achieved with @@ -464,17 +460,15 @@ class ErrorErasureChannel(Channel): We construct a ErrorErasureChannel which adds 2 errors and 2 erasures to any transmitted message:: - sage: F = VectorSpace(GF(59), 40) sage: n_err, n_era = 2, 2 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) sage: Chan Error-and-erasure channel creating 2 errors and 2 erasures We can also pass the number of errors and erasures as a couple of integers:: - sage: F = VectorSpace(GF(59), 40) sage: n_err, n_era = (1, 10), (1, 10) - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) sage: Chan Error-and-erasure channel creating between 1 and 10 errors and between 1 and 10 erasures """ @@ -489,9 +483,8 @@ def __init__(self, space, number_errors, number_erasures): exceeds (or may exceed, in the case of tuples) the dimension of the input space, it will return an error:: - sage: F = VectorSpace(GF(59), 40) sage: n_err, n_era = 21, 21 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) Traceback (most recent call last): ... ValueError: The total number of errors and erasures can not exceed the dimension of the input space @@ -519,9 +512,8 @@ def _repr_(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 50) sage: n_err, n_era = 21, 21 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^50, n_err, n_era) sage: Chan Error-and-erasure channel creating 21 errors and 21 erasures """ @@ -536,9 +528,8 @@ def _latex_(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 50) sage: n_err, n_era = 21, 21 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^50, n_err, n_era) sage: latex(Chan) \textnormal{Error-and-erasure channel creating 21 errors and 21 erasures} """ @@ -551,9 +542,10 @@ def transmit_unsafe(self, message): r""" Returns ``message`` with as many errors as ``self._number_errors`` in it, and as many erasures as ``self._number_erasures`` in it. + If ``self._number_errors`` was passed as an tuple for the number of errors, it will pick a random integer between the bounds of the tuple and use it as the number of errors. - The same method applies with ``self._number_erasures``. + It does the same with ``self._number_erasures``. All erased positions are set to 0 in the transmitted message. It is guaranteed that the erasures and the errors will never overlap: @@ -576,7 +568,7 @@ def transmit_unsafe(self, message): EXAMPLES:: - sage: F = VectorSpace(GF(59), 11) + sage: F = GF(59)^11 sage: n_err, n_era = 2, 2 sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3)) @@ -613,9 +605,8 @@ def number_errors(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) sage: n_err, n_era = 3, 0 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^6, n_err, n_era) sage: Chan.number_errors() (3, 3) """ @@ -627,9 +618,8 @@ def number_erasures(self): EXAMPLES:: - sage: F = VectorSpace(GF(59), 6) sage: n_err, n_era = 0, 3 - sage: Chan = channels.ErrorErasureChannel(F, n_err, n_era) + sage: Chan = channels.ErrorErasureChannel(GF(59)^6, n_err, n_era) sage: Chan.number_erasures() (3, 3) """ From 768ed9cd9e827fa833c9244cfade1ea63e703216 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 10:57:22 +0200 Subject: [PATCH 567/665] Simplified code in ErrorErasureChannel.transmit_unsafe --- src/sage/coding/channel_constructions.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 4b13603ddab..0d32ffcadfb 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -574,21 +574,16 @@ def transmit_unsafe(self, message): sage: msg = F((3, 14, 15, 9, 26, 53, 58, 9, 7, 9, 3)) sage: set_random_seed(10) sage: Chan.transmit_unsafe(msg) - ((32, 0, 15, 9, 8, 53, 58, 9, 0, 9, 3), (0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0)) + ((31, 0, 15, 9, 38, 53, 58, 9, 0, 9, 3), (0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0)) """ number_errors = randint(*self.number_errors()) number_erasures = randint(*self.number_erasures()) V = self.input_space() n = V.dimension() - erroneous_positions = sample(xrange(n),\ - number_errors + number_erasures) - error_split = sample(xrange(number_errors + number_erasures),\ - number_errors) - error_positions = [erroneous_positions[i] for i in\ - range(number_errors + number_erasures) if i in error_split] - erasure_positions = [erroneous_positions[i] for i in\ - range(number_errors + number_erasures) if i not in error_split] + errors = sample(xrange(n), number_errors + number_erasures) + error_positions = errors[:number_errors] + erasure_positions = errors[number_errors:] error_vector = random_error_vector(n, V.base_ring(), error_positions) erasure_vector = random_error_vector(n , GF(2), erasure_positions) From 629f6a5618ec6e5f616bf89e4886ea4dd92ae60e Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 27 Apr 2015 11:11:45 +0200 Subject: [PATCH 568/665] Improve comparisons for permutation groups --- .../groups/perm_gps/permgroup_element.pyx | 31 ++++++++----------- src/sage/rings/number_field/galois_group.py | 16 ---------- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index c0e2c7e81db..5e5fa6313b9 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -480,9 +480,6 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): if not is_valid_permutation(self.perm, vn): raise ValueError, "Invalid permutation vector: %s" % v - def __cinit__(self, g = None, parent = None, check = True): - self.perm = NULL - def __dealloc__(self): if self.perm is not NULL and self.perm is not self.perm_buf: sage_free(self.perm) @@ -622,9 +619,9 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): """ return self.cycles()[i] - def __cmp__(PermutationGroupElement self, PermutationGroupElement right): + cpdef int _cmp_(self, Element other) except -2: """ - Compare group elements self and right. + Compare group elements ``self`` and ``other``. EXAMPLES:: @@ -650,7 +647,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): TESTS: - Verify that we fixed bug #5537:: + Verify that we fixed bug :trac:`5537`:: sage: h = PermutationGroupElement('(1,3,2)') sage: k = PermutationGroupElement('(1,2,3),(4,5)') @@ -660,22 +657,20 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): True """ cdef int i - cdef int swap = 1 - if right.n < self.n: - self, right = right, self - swap = -1 - for i from 0 <= i < self.n: + cdef PermutationGroupElement right = other + for i in range(self.n): # Equal parents, so self.n == other.n if self.perm[i] < right.perm[i]: - return -swap + return -1 elif self.perm[i] > right.perm[i]: - return swap - for i from self.n <= i < right.n: - if i < right.perm[i]: - return -swap - elif i > right.perm[i]: - return swap + return 1 return 0 + def __richcmp__(left, right, int op): + return (left)._richcmp(right, op) + + def __cmp__(left, right): + return (left)._cmp(right) + def __call__(self, i): """ Returns the image of the integer i under this permutation. diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 1e14977a0b2..fe588fdda9e 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -635,7 +635,6 @@ class GaloisGroupElement(PermutationGroupElement): sage: G[4](G[4](G[4](v))) 1/18*y^4 """ - @cached_method def as_hom(self): r""" @@ -690,21 +689,6 @@ def ramification_degree(self, P): w = [ (self(g) - g).valuation(P) for g in gens] return min(w) - def __cmp__(self, other): - r""" - Compare self to other. For some bizarre reason, if you just let it - inherit the cmp routine from PermutationGroupElement, cmp(x, y) works - but sorting lists doesn't. - - TEST:: - - sage: K. = NumberField(x^6 + 40*x^3 + 1372);G = K.galois_group() - sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) - [(1,3)(2,6)(4,5), (1,2)(3,4)(5,6), (1,5)(2,4)(3,6)] - """ - return PermutationGroupElement.__cmp__(self, other) - - # For unpickling purposes we rebind GaloisGroup as GaloisGroup_v1. From c3b5555a8c0572e6acfce69d021d56f074b1398e Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 12:28:46 +0200 Subject: [PATCH 569/665] Replaced CartesianProduct by cartesian_product --- src/sage/coding/channel_constructions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 0d32ffcadfb..319f6294397 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -30,7 +30,7 @@ from sage.misc.prandom import randint, random, sample from sage.modules.free_module_element import vector from sage.misc.abstract_method import abstract_method -from sage.combinat.cartesian_product import CartesianProduct +from sage.categories.cartesian_product import cartesian_product from sage.modules.free_module import VectorSpace from copy import copy @@ -499,7 +499,7 @@ def __init__(self, space, number_errors, number_erasures): if not isinstance(number_erasures, (tuple, list)): raise ValueError("number_erasures must be a tuple, a list, an Integer or a Python int") - output_space = CartesianProduct(space, VectorSpace(GF(2), space.dimension())) + output_space = cartesian_product([space, VectorSpace(GF(2), space.dimension())]) super(ErrorErasureChannel, self).__init__(space, output_space) if number_errors[1] + number_erasures[1] > space.dimension(): raise ValueError("The total number of errors and erasures can not exceed the dimension of the input space") From ef2a71fe8ade2060f90df420ee94f7238f9a511e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 27 Apr 2015 12:23:28 +0200 Subject: [PATCH 570/665] trac #17662: Review --- .../designs/evenly_distributed_sets.pyx | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 2aef57e0fdb..ca2bd4bfb4c 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -55,9 +55,10 @@ cdef class EvenlyDistributedSetsBacktracker: By default, this backtracker only considers evenly distributed sets up to affine automorphisms, i.e. `B` is considered equivalent to `s B + t` for any invertible element `s` and any element `t` in the field `K`. Note that the - set of differences is just multiplicatively translated by `s` as - `\Delta (s B + t) = s (\Delta B)`. This can be modified via the argument - ``up_to_isomorphisms`` (see the input section and the examples below). + set of differences is just multiplicatively translated by `s` as `\Delta (s + B + t) = s (\Delta B)`, and so that `B` is an evenly distributed set if and + only if `sB` is one too. This behaviour can be modified via the argument + ``up_to_isomorphism`` (see the input section and the examples below). INPUT: @@ -66,7 +67,7 @@ cdef class EvenlyDistributedSetsBacktracker: - ``k`` -- a positive integer such that `k(k-1)` divides `q-1` - ``up_to_isomorphism`` - (boolean, default ``True``) whether only consider - evenly distributed set up to automorphisms of the field of the form + evenly distributed sets up to automorphisms of the field of the form `x \mapsto ax + b`. - ``check`` -- boolean (default is ``False``). Whether you want to check @@ -161,7 +162,7 @@ cdef class EvenlyDistributedSetsBacktracker: # DYNAMIC DATA cdef unsigned int * B # current stack of elements of {0,...,q-1} - cdef unsigned int * cosets # cosets of differences of elts in B + cdef unsigned int * cosets # e array: cosets of differences of elts in B cdef unsigned int * t # temporary variable for updates def __dealloc__(self): @@ -243,7 +244,7 @@ cdef class EvenlyDistributedSetsBacktracker: self.min_orb[0] = self.min_orb[q-1] = 0 for i,x in enumerate(self.list_K): if x != zero and x != one: - self.min_orb[i] = min(K_to_int[z] for z in \ + self.min_orb[i] = min(K_to_int[z] for z in [x, one/x, one-x, one/(one-x), (x-one)/x, x/(x-one)]) for j,y in enumerate(self.list_K): self.diff[i][j] = K_to_int[x-y] @@ -408,6 +409,8 @@ cdef class EvenlyDistributedSetsBacktracker: else: tmp2 = self.ratio[self.diff[self.B[k]][self.B[i]]][tmp1] if tmp2 == 0 or tmp2 == self.q-1 or tmp2 < self.B[2]: + # the backtracker should never build a set which by + # relabelling is strictly smaller than B[:3] raise RuntimeError("there is a problem got tmp2={}".format(tmp2,self.B[2])) elif tmp2 == self.B[2]: verify = 1 @@ -456,14 +459,13 @@ cdef class EvenlyDistributedSetsBacktracker: B[1] = 0 # the element 1 in K memset(self.cosets, 0, e * sizeof(unsigned int)) - memset(self.t, 0, e * sizeof(unsigned int)) - self.cosets[0] = 1 # the coset of 1 + self.cosets[0] = 1 # coset 0 is hit by the difference 1-0 cdef unsigned int x = m while True: if self.check: - self._check(kk) + self._check_cosets(kk) assert m < x < q-1, "got x < m or x > q where x={}".format(x) # try to append x @@ -498,16 +500,20 @@ cdef class EvenlyDistributedSetsBacktracker: if x == q-2: raise RuntimeError("this is impossible!") + x += 1 + if kk == 1: return - x += 1 - @cython.cdivision(True) cdef inline int _add_element(self, unsigned int x, unsigned int kk) except -1: r""" Add the element ``x`` to ``B`` in position kk if the resulting set is still evenly distributed. + + OUTPUT: + + 1 if the element was added, and 0 otherwise. """ cdef unsigned int i, j, x_m_i, x_m_j cdef unsigned int m = (self.q-1)/self.e @@ -537,20 +543,22 @@ cdef class EvenlyDistributedSetsBacktracker: if self.min_orb[self.ratio[x_m_i][x_m_j]] < self.B[2]: return 0 + memset(self.t, 0, self.e*sizeof(unsigned int)) + # Next we compute the cosets hit by the differences for j in range(kk): i = self.diff[x][self.B[j]] / m if self.cosets[i] or self.t[i]: - memset(self.t, 0, self.e*sizeof(unsigned int)) return 0 self.t[i] = 1 # If everything went smoothly, we add x to B self.B[kk] = x + + # coset = cosets (union) t for i in range(self.e): - if self.t[i]: - self.cosets[i] = 1 - self.t[i] = 0 + self.cosets[i] |= self.t[i] + return 1 cdef inline void _pop(self, unsigned int kk): @@ -565,7 +573,7 @@ cdef class EvenlyDistributedSetsBacktracker: i = self.diff[x][self.B[j]] / m self.cosets[i] = 0 - cdef int _check(self, unsigned int kk) except -1: + cdef int _check_cosets(self, unsigned int kk) except -1: r""" Sanity check (only for debug purposes). """ From 6dd51f3e3ed8494599f9bd1ad7a9b17145fd2b15 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 12:38:50 +0200 Subject: [PATCH 571/665] New test in transmit method. Replaced 0 by the zero of the base ring of the input space in ErrorErasureChannel.transmit_unsafe --- src/sage/coding/channel_constructions.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index 319f6294397..fc942183e9e 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -168,6 +168,7 @@ def transmit(self, message): transmitted through. Checks if ``message`` belongs to the input space, and returns an exception if not. + Note that ``message`` itself is never modified by the channel. INPUT: @@ -187,6 +188,11 @@ def transmit(self, message): sage: Chan.transmit(msg) (4, 8, 4, 16, 23, 53) + We can check that the input ``msg`` is not modified:: + + sage: msg + (4, 8, 15, 16, 23, 42) + If we transmit a vector which is not in the input space of ``self``:: sage: n_err = 2 @@ -580,6 +586,7 @@ def transmit_unsafe(self, message): number_erasures = randint(*self.number_erasures()) V = self.input_space() n = V.dimension() + zero = V.base_ring().zero() errors = sample(xrange(n), number_errors + number_erasures) error_positions = errors[:number_errors] @@ -591,7 +598,7 @@ def transmit_unsafe(self, message): message = message + error_vector for i in erasure_positions: - message[i] = 0 + message[i] = zero return message, erasure_vector def number_errors(self): From 383e67c01119ce17f0ab58fd0833016a9bcdad01 Mon Sep 17 00:00:00 2001 From: David Lucas Date: Mon, 27 Apr 2015 13:05:10 +0200 Subject: [PATCH 572/665] Changed _repr_ and _latex_ methods --- src/sage/coding/channel_constructions.py | 47 ++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/sage/coding/channel_constructions.py b/src/sage/coding/channel_constructions.py index fc942183e9e..2a6a14f1120 100644 --- a/src/sage/coding/channel_constructions.py +++ b/src/sage/coding/channel_constructions.py @@ -304,14 +304,16 @@ class StaticErrorRateChannel(Channel): sage: n_err = 2 sage: Chan = channels.StaticErrorRateChannel(GF(59)^40, n_err) sage: Chan - Static error rate channel creating 2 errors + Static error rate channel creating 2 errors, of input and output space + Vector space of dimension 40 over Finite Field of size 59 We can also pass a tuple for the number of errors:: sage: n_err = (1, 10) sage: Chan = channels.StaticErrorRateChannel(GF(59)^40, n_err) sage: Chan - Static error rate channel creating between 1 and 10 errors + Static error rate channel creating between 1 and 10 errors, + of input and output space Vector space of dimension 40 over Finite Field of size 59 """ def __init__(self, space, number_errors): @@ -345,11 +347,12 @@ def _repr_(self): sage: n_err = 42 sage: Chan = channels.StaticErrorRateChannel(GF(59)^50, n_err) sage: Chan - Static error rate channel creating 42 errors + Static error rate channel creating 42 errors, of input and output space + Vector space of dimension 50 over Finite Field of size 59 """ no_err = self.number_errors() - return "Static error rate channel creating %s errors"\ - % (format_interval(no_err)) + return "Static error rate channel creating %s errors, of input and output space %s"\ + % (format_interval(no_err), self.input_space()) def _latex_(self): r""" @@ -359,12 +362,13 @@ def _latex_(self): sage: n_err = 42 sage: Chan = channels.StaticErrorRateChannel(GF(59)^50, n_err) - sage: Chan._latex_() - '\\textnormal{Static error rate channel, creating }42 \\textnormal{ error(s)}' + sage: latex(Chan) + \textnormal{Static error rate channel creating 42 errors, of + input and output space Vector space of dimension 50 over Finite Field of size 59} """ no_err = self.number_errors() - return "\\textnormal{Static error rate channel, creating }%s \\textnormal{ error(s)}"\ - % format_interval(no_err) + return "\\textnormal{Static error rate channel creating %s errors, of input and output space %s}"\ + % (format_interval(no_err), self.input_space()) def transmit_unsafe(self, message): r""" @@ -470,13 +474,20 @@ class ErrorErasureChannel(Channel): sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) sage: Chan Error-and-erasure channel creating 2 errors and 2 erasures + of input space Vector space of dimension 40 over Finite Field of size 59 + and output space The cartesian product of (Vector space of dimension 40 + over Finite Field of size 59, Vector space of dimension 40 over Finite Field of size 2) We can also pass the number of errors and erasures as a couple of integers:: sage: n_err, n_era = (1, 10), (1, 10) sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) sage: Chan - Error-and-erasure channel creating between 1 and 10 errors and between 1 and 10 erasures + Error-and-erasure channel creating between 1 and 10 errors and + between 1 and 10 erasures of input space Vector space of dimension 40 + over Finite Field of size 59 and output space The cartesian product of + (Vector space of dimension 40 over Finite Field of size 59, + Vector space of dimension 40 over Finite Field of size 2) """ def __init__(self, space, number_errors, number_erasures): @@ -522,11 +533,14 @@ def _repr_(self): sage: Chan = channels.ErrorErasureChannel(GF(59)^50, n_err, n_era) sage: Chan Error-and-erasure channel creating 21 errors and 21 erasures + of input space Vector space of dimension 50 over Finite Field of size 59 + and output space The cartesian product of (Vector space of dimension 50 + over Finite Field of size 59, Vector space of dimension 50 over Finite Field of size 2) """ no_err = self.number_errors() no_era = self.number_erasures() - return "Error-and-erasure channel creating %s errors and %s erasures"\ - % (format_interval(no_err), format_interval(no_era)) + return "Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s"\ + % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) def _latex_(self): r""" @@ -537,12 +551,15 @@ def _latex_(self): sage: n_err, n_era = 21, 21 sage: Chan = channels.ErrorErasureChannel(GF(59)^50, n_err, n_era) sage: latex(Chan) - \textnormal{Error-and-erasure channel creating 21 errors and 21 erasures} + \textnormal{Error-and-erasure channel creating 21 errors and 21 erasures + of input space Vector space of dimension 50 over Finite Field of size 59 + and output space The cartesian product of (Vector space of dimension 50 + over Finite Field of size 59, Vector space of dimension 50 over Finite Field of size 2)} """ no_err = self.number_errors() no_era = self.number_erasures() - return "\\textnormal{Error-and-erasure channel creating %s errors and %s erasures}"\ - % (format_interval(no_err), format_interval(no_era)) + return "\\textnormal{Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s}"\ + % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) def transmit_unsafe(self, message): r""" From 0d1e049f807a1c34b00cf0e58ee65cc7734d1ad1 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 27 Apr 2015 11:09:17 +0200 Subject: [PATCH 573/665] Improve _richcmp and documentation --- .../nf_galois_groups.rst | 2 +- src/sage/matrix/matrix_mod2_dense.pyx | 6 +- src/sage/modules/vector_modn_dense.pyx | 14 +- src/sage/structure/element.pyx | 149 ++++++++++++------ 4 files changed, 109 insertions(+), 62 deletions(-) diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst index e497a5cbb47..585dbd51d4f 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst @@ -41,7 +41,7 @@ Some more advanced number-theoretical tools are available via G: sage: P = K.primes_above(2)[0] sage: G.inertia_group(P) Subgroup [(), (1,4,6)(2,5,3), (1,6,4)(2,3,5)] of Galois group of Number Field in alpha with defining polynomial x^6 + 40*x^3 + 1372 - sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) + sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) # random order, see Trac #18308 [(1,3)(2,6)(4,5), (1,2)(3,4)(5,6), (1,5)(2,4)(3,6)] If the number field is not Galois over `\QQ`, then the ``galois_group`` diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index e14177b2776..d38dbac76db 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -268,7 +268,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse mzd_write_bit(self._entries,i,j, R(entries[k])) k = k + 1 - def __richcmp__(Matrix self, right, int op): # always need for mysterious reasons. + def __richcmp__(Matrix self, right, int op): """ Compares ``self`` with ``right``. While equality and inequality are clearly defined, ``<`` and ``>`` are not. For @@ -286,10 +286,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse EXAMPLE:: - sage: A = random_matrix(GF(2),2,2) - sage: B = random_matrix(GF(2),3,3) - sage: A < B - True sage: A = MatrixSpace(GF(2),3,3).one() sage: B = copy(MatrixSpace(GF(2),3,3).one()) sage: B[0,1] = 1 diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index 12e013cfdf3..71308fe575a 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -162,13 +162,12 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): self._entries[i] = 0 def __dealloc__(self): - cdef Py_ssize_t i - if self._entries: - sage_free(self._entries) + sage_free(self._entries) cpdef int _cmp_(left, Element right) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: v = vector(GF(5), [0,0,0,0]) sage: v == 0 True @@ -176,11 +175,6 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): False sage: v == v True - sage: w = vector(GF(11), [1,0,0,0]) - sage: w < v - True - sage: w > v - False """ cdef Py_ssize_t i cdef mod_int l, r @@ -192,7 +186,7 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): elif l > r: return 1 return 0 - # see sage/structure/element.pyx + def __richcmp__(left, right, int op): """ TEST:: diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index d1c17558419..eee01f21e0b 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -100,7 +100,7 @@ underscores). module to work out how to make them have the same parent. After any necessary coercions have been performed, it calls ``_add_`` to dispatch to the correct underlying addition implementation. - + Note that although this function is declared as ``def``, it doesn't have the usual overheads associated with Python functions (either for the caller or for ``__add__`` itself). This is because Python has optimised calling @@ -311,16 +311,16 @@ cdef class Element(SageObject): Subtypes must either call ``__init__()`` to set ``_parent``, or may set ``_parent`` themselves if that would be more efficient. - """ + .. automethod:: _cmp_ + .. automethod:: _richcmp_ + """ def __init__(self, parent): r""" INPUT: - ``parent`` - a SageObject """ - #if parent is None: - # raise RuntimeError, "bug -- can't set parent to None" self._parent = parent def _set_parent(self, parent): @@ -745,8 +745,8 @@ cdef class Element(SageObject): from sage.misc.functional import numerical_approx return numerical_approx(self, prec=prec, digits=digits, algorithm=algorithm) - n = numerical_approx - N = n + n = numerical_approx + N = n def _mpmath_(self, prec=53, rounding=None): """ @@ -807,7 +807,7 @@ cdef class Element(SageObject): cpdef _act_on_(self, x, bint self_on_left): """ - Use this method to implement ``self`` acting on x. + Use this method to implement ``self`` acting on ``x``. Return None or raise a CoercionException if no such action is defined here. @@ -931,46 +931,76 @@ cdef class Element(SageObject): # Same parents return left._cmp_(right) - cdef _richcmp(left, right, int op): + cdef _richcmp(self, other, int op): """ - Compare left and right, according to the comparison operator op. + Compare ``self`` and ``other`` using the coercion framework, + comparing according to the comparison operator ``op``. + + This method exists only because of the strange way that Python + handles inheritance of ``__richcmp__``. A Cython class should + always define ``__richcmp__`` as calling ``_richcmp``. + + Normally, a class will not redefine ``_richcmp`` but rely on + this ``Element._richcmp`` method which uses coercion to + compare elements. Then ``_richcmp_`` is called on the coerced + elements. + + If a class wants to implement rich comparison without coercion, + then ``_richcmp`` should be defined (as well as ``__richcmp__`` + as usual). """ - global coercion_model - cdef int r - if not have_same_parent_c(left, right): - if left is None or left is Ellipsis: - return rich_to_bool(op, -1) - elif right is None or right is Ellipsis: - return rich_to_bool(op, 1) - try: - _left, _right = coercion_model.canonical_coercion(left, right) - if isinstance(_left, Element): - return (_left)._richcmp(_right, op) - return rich_to_bool(op, cmp(_left, _right)) - except (TypeError, NotImplementedError): - r = cmp(type(left), type(right)) - if r == 0: - r = -1 - # Often things are compared against 0 (or 1), even when there - # is not a canonical coercion ZZ -> other - # Things should implement and/or use __nonzero__ and is_one() - # but we can't do that here as that calls this. - # The old coercion model would declare a coercion if 0 went in. - # (Though would fail with a TypeError for other values, thus - # contaminating the _has_coerce_map_from cache.) - from sage.rings.integer import Integer - try: - if isinstance(left, Element) and isinstance(right, (int, float, Integer)) and not right: - right = (left)._parent(right) - elif isinstance(right, Element) and isinstance(left, (int, float, Integer)) and not left: - left = (right)._parent(left) - else: - return rich_to_bool(op, r) - except TypeError: - return rich_to_bool(op, r) + if have_same_parent_c(self, other): + # Same parents, in particular other must be an Element too. + # The explicit cast other tells Cython to omit the + # check isinstance(other, Element) when calling _richcmp_ + return self._richcmp_(other, op) - # Same parents - return left._richcmp_(right, op) + # Some very special cases + if self is None or self is Ellipsis: + return rich_to_bool(op, -1) + if other is None or other is Ellipsis: + return rich_to_bool(op, 1) + + # Different parents => coerce + try: + left, right = coercion_model.canonical_coercion(self, other) + if isinstance(left, Element): + return (left)._richcmp(right, op) + # left and right are the same non-Element type: + # use a plain cmp() + return rich_to_bool(op, cmp(left, right)) + except (TypeError, NotImplementedError): + pass + + # Comparing with coercion didn't work, try something else. + + # Often things are compared against 0, even when there is no + # canonical coercion from ZZ. For ModuleElements, we manually + # convert zero to handle this case. + from sage.rings.integer import Integer + cdef Element zero + try: + if isinstance(self, ModuleElement) and isinstance(other, (int, float, Integer)) and not other: + zero = (self)._parent(0) + return self._richcmp_(zero, op) + elif isinstance(other, ModuleElement) and isinstance(self, (int, float, Integer)) and not self: + zero = (other)._parent(0) + return zero._richcmp_(other, op) + except (TypeError, AttributeError): + pass + + # If types are not equal: compare types + cdef int r = cmp(type(self), type(other)) + if r: + return rich_to_bool(op, r) + + # Final attempt: compare by id() + if (self) >= (other): + # It cannot happen that self is other, since they don't + # have the same parent. + return rich_to_bool(op, 1) + else: + return rich_to_bool(op, -1) #################################################################### # For a derived Cython class, you **must** put the __richcmp__ @@ -993,6 +1023,30 @@ cdef class Element(SageObject): return (left)._cmp(right) cpdef _richcmp_(left, Element right, int op): + r""" + Default implementation of rich comparisons for elements with + equal parents. + + It tries to see if ``_cmp_`` is implemented. Otherwise it does a + comparison by id for ``==`` and ``!=``. Calling this default method + with ``<``, ``<=``, ``>`` or ``>=`` will raise a + ``NotImplementedError``. + + EXAMPLES:: + + sage: from sage.structure.parent import Parent + sage: from sage.structure.element import Element + sage: P = Parent() + sage: e1 = Element(P); e2 = Element(P) + sage: e1 == e1 # indirect doctest + True + sage: e1 == e2 # indirect doctest + False + sage: e1 < e2 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: comparison not implemented for + """ # Obvious case if left is right: return rich_to_bool(op, 0) @@ -1009,7 +1063,10 @@ cdef class Element(SageObject): return rich_to_bool(op, c) cpdef int _cmp_(left, Element right) except -2: - # Check for Python class defining __cmp__ + """ + Default three-way comparison method which only checks for a + Python class defining ``__cmp__``. + """ left_cmp = left.__cmp__ if isinstance(left_cmp, MethodType): return left_cmp(right) @@ -2996,7 +3053,7 @@ def is_PrincipalIdealDomainElement(x): cdef class PrincipalIdealDomainElement(DedekindDomainElement): def lcm(self, right): """ - Return the least common multiple of ``self`` and right. + Return the least common multiple of ``self`` and ``right``. """ if not isinstance(right, Element) or not ((right)._parent is self._parent): from sage.rings.arith import lcm From 0a750d920a445e864b9fbf666a9e6c4d0776eb21 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:28:25 +0200 Subject: [PATCH 574/665] Trac 17662: fix _check_cosets method --- .../designs/evenly_distributed_sets.pyx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index ca2bd4bfb4c..8893c2a60c9 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -577,13 +577,20 @@ cdef class EvenlyDistributedSetsBacktracker: r""" Sanity check (only for debug purposes). """ - cdef unsigned int i,j,x,y - cdef set s = set() + cdef unsigned int i,j + cdef unsigned int m = self.m + cdef unsigned int c + + # count the number of elements in self.cosets + c = 0 + for i in range(self.e): + c += self.cosets[i] + if c != kk * (kk-1) / 2: + raise RuntimeError("the number of elements in cosets is wrong! Got {} instead of {}.".format(c, kk*(kk-1))) + for i in range(kk): - x = self.B[i] for j in range(i): - y = self.B[j] - s.add(self.diff_to_coset[x][y]) + if self.cosets[ self.diff[self.B[i]][self.B[j]] / m ] != 1: + raise RuntimeError("self.cosets misses the difference B[{}]-B[{}]".format(i,j)) - if set(j for j in range(self.e) if self.cosets[j]) != s: - raise RuntimeError("self.cosets is not synchronized with self.B!") + return 0 From 9343425c34ecb4c862a2f124f8402999fd76dbeb Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:30:31 +0200 Subject: [PATCH 575/665] Trac 17662: check argument in to_difference_family --- .../designs/evenly_distributed_sets.pyx | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 8893c2a60c9..adb4574b8a3 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -1,3 +1,4 @@ +# coding=utf-8 r""" Evenly distributed sets in finite fields @@ -253,7 +254,8 @@ cdef class EvenlyDistributedSetsBacktracker: else: self.ratio[i][j] = UINT_MAX - def to_difference_family(self, B): + + def to_difference_family(self, B, check=True): r""" Given an evenly distributed set ``B`` convert it to a difference family. @@ -264,6 +266,12 @@ cdef class EvenlyDistributedSetsBacktracker: This method is useful if you want to obtain the difference family from the output of the iterator. + INPUT: + + - ``B`` -- an evenly distributed set + + - ``check`` -- (boolean, default ``True``) whether to check the result + EXAMPLES:: sage: from sage.combinat.designs.evenly_distributed_sets import EvenlyDistributedSetsBacktracker @@ -276,9 +284,26 @@ cdef class EvenlyDistributedSetsBacktracker: sage: from sage.combinat.designs.difference_family import is_difference_family sage: is_difference_family(Zmod(41),D,41,5,1) True + + Setting ``check`` to ``False`` is much faster:: + + sage: timeit("df = E.to_difference_family(B, check=True)") # random + 625 loops, best of 3: 117 µs per loop + + sage: timeit("df = E.to_difference_family(B, check=False)") # random + 625 loops, best of 3: 1.83 µs per loop """ xe = self.K.multiplicative_generator() ** (self.e) - return [[xe**j*b for b in B] for j in range((self.q-1)/(2*self.e))] + df = [[xe**j*b for b in B] for j in range((self.q-1)/(2*self.e))] + if check: + from difference_family import is_difference_family + if not is_difference_family(self.K, df, self.q, self.k, 1): + raise RuntimeError("a wrong evenly distributed set was " + "produced by the Sage library for the parameters:\n" + " q={} k={}\n" + "Please send an e-mail to " + "sage-devel@googlegroups.com".format(self.q, self.k)) + return df def an_element(self): r""" @@ -307,6 +332,7 @@ cdef class EvenlyDistributedSetsBacktracker: B = it.next() except StopIteration: raise EmptySetError("no {}-evenly distributed set in {}".format(self.k,self.K)) + self.to_difference_family(B, check=True) # check the validity return B def __repr__(self): From dc17b775b16b47ddc67cb39c00bcd8680075054f Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:39:47 +0200 Subject: [PATCH 576/665] Trac 17662: _B_automorphisms -> _B_relabelled_copies --- src/sage/combinat/designs/evenly_distributed_sets.pyx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index adb4574b8a3..7b59010155b 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -381,9 +381,9 @@ cdef class EvenlyDistributedSetsBacktracker: self.count = 0 return smallInteger(n) - def _B_automorphisms(self): + def _B_relabelled_copies(self): r""" - Check whether `self.B` is minimal among its relabelization. + Check whether ``self.B`` is minimal among its relabelization. If `B=\{b_1,...,b_k\}` is an evenly distributed set and contains `0` and `1`, then for any two distinct `i,j` we define `f_{ij} : x \mapsto @@ -412,6 +412,12 @@ cdef class EvenlyDistributedSetsBacktracker: sage: E = EvenlyDistributedSetsBacktracker(Zmod(13), 4, up_to_isomorphism=False) sage: E.cardinality() # indirect doctest 4 + + .. NOTE:: + + this method is not seriously optimized. The main goal of this backtracker + is to generate one evenly distributed set. In that case, this method + will be called only once. """ cdef unsigned int i,j,k,tmp1,tmp2,verify cdef list B = [self.B[i] for i in range(1,self.k)] From d25ced13ecc236197dc3da787699d141061192e4 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:33:38 +0200 Subject: [PATCH 577/665] Trac 17662: more check and better iterator --- .../designs/evenly_distributed_sets.pyx | 197 ++++++++++-------- 1 file changed, 110 insertions(+), 87 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 7b59010155b..c276fc9779f 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -21,7 +21,7 @@ include "sage/ext/stdsage.pxi" cimport cython from libc.limits cimport UINT_MAX -from libc.string cimport memset +from libc.string cimport memset, memcpy from sage.ext.memory cimport check_malloc, check_calloc @@ -156,6 +156,7 @@ cdef class EvenlyDistributedSetsBacktracker: cdef unsigned int q # cardinality of the field cdef unsigned int k # size of the subsets cdef unsigned int e # k(k-1)/2 + cdef unsigned int m # (q-1) / e cdef unsigned int ** diff # qxq array: diff[x][y] = x - y cdef unsigned int ** ratio # qxq array: ratio[x][y] = x / y cdef unsigned int * min_orb # q array : min_orb[x] = min {x, 1-x, 1/x, @@ -211,6 +212,7 @@ cdef class EvenlyDistributedSetsBacktracker: self.q = q self.e = e self.k = k + self.m = (q-1) / e self.K = K self.diff = check_calloc(q, sizeof(unsigned int *)) @@ -254,7 +256,6 @@ cdef class EvenlyDistributedSetsBacktracker: else: self.ratio[i][j] = UINT_MAX - def to_difference_family(self, B, check=True): r""" Given an evenly distributed set ``B`` convert it to a difference family. @@ -476,10 +477,9 @@ cdef class EvenlyDistributedSetsBacktracker: ....: print B [0, 1, 11, 5] """ - cdef unsigned int k = self.k - cdef unsigned int q = self.q - cdef unsigned int e = self.e - cdef unsigned int m = (q-1) / e + cdef unsigned int k_m_1 = self.k - 1 + cdef unsigned int q_m_1 = self.q - 1 + cdef unsigned int m = self.m # in the list B we store the candidate for being an e.d.s. # we always have B[0] = 0 and B[1] = 1 @@ -487,10 +487,10 @@ cdef class EvenlyDistributedSetsBacktracker: # disjoint. cdef unsigned int kk = 2 cdef unsigned int * B = self.B - B[0] = q-1 # the element 0 in K - B[1] = 0 # the element 1 in K + B[0] = q_m_1 # the element 0 in K + B[1] = 0 # the element 1 in K - memset(self.cosets, 0, e * sizeof(unsigned int)) + memset(self.cosets, 0, self.e * sizeof(unsigned int)) self.cosets[0] = 1 # coset 0 is hit by the difference 1-0 @@ -498,47 +498,71 @@ cdef class EvenlyDistributedSetsBacktracker: while True: if self.check: self._check_cosets(kk) - assert m < x < q-1, "got x < m or x > q where x={}".format(x) + if x < m or x >= q_m_1: + raise RuntimeError("got x < m or x > q_m_1 (x={})".format(x)) + if self.cosets[x/m]: + raise RuntimeError("got x={} in an already occuppied coset".format(x)) # try to append x - if self._add_element(x,kk): - # note: the element x is already added to B in ._add_element() - if kk == k-1: - ans = self._B_automorphisms() + B[kk] = x + if self._check_last_element(kk): + if kk == k_m_1: + ans = self._B_relabelled_copies() + + if self.check and ans: + for a in ans: + r = [self.list_K[q_m_1]] + [self.list_K[a[r]] for r in range(k_m_1)] + self.to_difference_family(r, check=True) + if ans is False: - continue + pass elif self.count: yield len(ans) else: for a in ans: - yield [self.list_K[q-1]] + [self.list_K[a[r]] for r in range(k-1)] - self._pop(kk) + yield [self.list_K[q_m_1]] + [self.list_K[a[r]] for r in range(k_m_1)] + + # remove the differences created by x and increment + for j in range(kk): + self.cosets[ self.diff[x][B[j]] / m ] = 0 + x += 1 else: - # we need to choose the next element from a new coset. In - # order to jump we artificially set x to the last element of - # the coset. - x += m - x%m - 1 kk += 1 + x += m - x%m + else: + x += 1 + + if self.check: + self._check_cosets(kk) # now we determine the next element x to be tested - if x == q-2: - kk -= 1 - x = B[kk] - self._pop(kk) - if x == q-2: + while True: + if kk == 1: + return + elif x == q_m_1: kk -= 1 - x = B[kk] - self._pop(kk) - if x == q-2: - raise RuntimeError("this is impossible!") - - x += 1 - - if kk == 1: - return + x = self.B[kk] + # remove the differences created by x and increment + for j in range(kk): + self.cosets[ self.diff[x][B[j]] / m ] = 0 + x += 1 + if self.check: + self._check_cosets(kk) + elif self.cosets[x / m]: + x += m - x%m + elif kk == 2: + if self.min_orb[x] < x: + x += 1 + else: + break + else: + if self.min_orb[x] < B[2]: + x += 1 + else: + break @cython.cdivision(True) - cdef inline int _add_element(self, unsigned int x, unsigned int kk) except -1: + cdef inline int _check_last_element(self, unsigned int kk) except -1: r""" Add the element ``x`` to ``B`` in position kk if the resulting set is still evenly distributed. @@ -548,62 +572,61 @@ cdef class EvenlyDistributedSetsBacktracker: 1 if the element was added, and 0 otherwise. """ cdef unsigned int i, j, x_m_i, x_m_j - cdef unsigned int m = (self.q-1)/self.e - - # We first check that applying some automorphisms we will not get an - # element smaller than B[2]. We should test all linear functions that - # send a subset of the form {x, B[i], B[j]} to {0, 1, z}. - # Given one such function, the values of the other are 1/z, 1-z, - # 1/(1-z), (z-1)/z and z/(z-1). The attribute 'min_orbit[z]' is - # exactly the minimum among these values. - # So it is enough to test one of these functions. We choose - # t -> (x - t)/ (x - B[j]) - # (that maps x to 0 and B[i] to 1). Its value at B[i] is just - # z = (x - B[i]) / (x - B[j]). + cdef unsigned int m = self.m + cdef unsigned int * B = self.B + cdef unsigned int ** diff = self.diff + cdef unsigned int x = B[kk] + + # We check two things: + # 1. that the newly created differences x-B[i] will not be in a coset + # already occuppied # - # In the special case when kk=2, or equivalently when we are testing if x - # fits as a new B[2], then we just check that x is the minimum among - # {x, 1/x, 1-x, 1/(1-x), (x-1)/x and x/(x-1)}. - if kk == 2: - if self.min_orb[x] < x: - return 0 - else: - for i in range(1,kk): - x_m_i = self.diff[x][self.B[i]] - for j in range(i): - x_m_j = self.diff[x][self.B[j]] - if self.min_orb[self.ratio[x_m_i][x_m_j]] < self.B[2]: - return 0 - - memset(self.t, 0, self.e*sizeof(unsigned int)) - - # Next we compute the cosets hit by the differences - for j in range(kk): - i = self.diff[x][self.B[j]] / m - if self.cosets[i] or self.t[i]: - return 0 - self.t[i] = 1 + # 2. that applying some automorphisms we will not get an + # element smaller than B[2]. We should test all linear functions that + # send a subset of the form {x, B[i], B[j]} to {0, 1, z}. + # Given one such function, the values of the other functions can be + # easily deduced: the value different from 0/1 are 1/z, 1-z, + # 1/(1-z), (z-1)/z and z/(z-1). The attribute 'min_orbit[z]' is + # exactly the minimum among these values. + # So it is enough to test one of these functions. We choose + # t -> (x - t)/ (x - B[j]) + # (that maps x to 0 and B[j] to 1). Its value at B[i] is just + # z = (x - B[i]) / (x - B[j]). + # + # In the special case when kk=2, or equivalently when we are testing if x + # fits as a new B[2], then we just check that x is the minimum among + # {x, 1/x, 1-x, 1/(1-x), (x-1)/x and x/(x-1)}. - # If everything went smoothly, we add x to B - self.B[kk] = x + if self.cosets[diff[x][0] / m] == 1: + return 0 - # coset = cosets (union) t - for i in range(self.e): - self.cosets[i] |= self.t[i] + self.cosets[x / m] = 1 + for i in range(2,kk): + x_m_i = diff[x][B[i]] - return 1 + # check that the difference x-B[i] was not already in an + # occuppied coset + if self.cosets[x_m_i / m]: + self.cosets[x / m] = 0 + return 0 - cdef inline void _pop(self, unsigned int kk): - r""" - Pop the element of ``self.B`` at position ``kk`` and updates - ``self.cosets`` - """ - cdef unsigned int i,j,x - cdef unsigned int m = (self.q-1)/self.e - x = self.B[kk] - for j in range(kk): - i = self.diff[x][self.B[j]] / m - self.cosets[i] = 0 + # check relabeling + for j in range(i): + x_m_j = diff[x][B[j]] + if self.min_orb[self.ratio[x_m_i][x_m_j]] < B[2]: + self.cosets[x / m] = 0 + return 0 + + # Now check that the x-B[i] belongs to distinct cosets + memcpy(self.t, self.cosets, self.e*sizeof(unsigned int)) + for i in range(1,kk): + x_m_i = diff[x][B[i]] / m + if self.t[x_m_i]: + self.cosets[x / m] = 0 + return 0 + self.t[x_m_i] = 1 + self.t, self.cosets = self.cosets, self.t + return 1 cdef int _check_cosets(self, unsigned int kk) except -1: r""" From 9aab4a879de86983eff5334c47307197ce23306a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:35:12 +0200 Subject: [PATCH 578/665] Trac 17662: fix wrong doctest + doctest with check=True --- .../designs/evenly_distributed_sets.pyx | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index c276fc9779f..d40faf84675 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -108,6 +108,8 @@ cdef class EvenlyDistributedSetsBacktracker: sage: for B in E: print B [0, 1, 11, 5] + + Or only count them:: sage: for k in range(13, 200, 12): @@ -121,14 +123,14 @@ cdef class EvenlyDistributedSetsBacktracker: 37 12 1 49 24 2 61 12 1 - 73 12 1 - 97 24 2 - 109 60 5 - 121 168 14 - 157 24 2 - 169 60 5 - 181 84 7 - 193 168 14 + 73 48 4 + 97 64 6 + 109 72 6 + 121 240 20 + 157 96 8 + 169 240 20 + 181 204 17 + 193 336 28 Note that by definition, the number of evenly distributed sets up to isomorphisms is at most `k(k-1)` times smaller than without isomorphisms. @@ -194,6 +196,18 @@ cdef class EvenlyDistributedSetsBacktracker: Traceback (most recent call last): ... ValueError: k(k-1)=42 does not divide q-1=70 + + For `q=421` which is congruent to 1 modulo `12`, `20`, `30` and `42` we + run backtracker with the ``check`` argument set to ``True``:: + + sage: for _ in EvenlyDistributedSetsBacktracker(Zmod(421), 4, check=True): + ....: pass + sage: for _ in EvenlyDistributedSetsBacktracker(Zmod(421), 5, check=True): + ....: pass + sage: for _ in EvenlyDistributedSetsBacktracker(Zmod(421), 6, check=True): + ....: pass + sage: for _ in EvenlyDistributedSetsBacktracker(Zmod(421), 7, check=True): + ....: pass """ self.check = bool(check) self.up_to_isom = bool(up_to_isomorphism) From 7224a147e9af6bb37a891e6536aa10fbf3135bd6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 27 Apr 2015 15:38:08 +0200 Subject: [PATCH 579/665] Trac 17662: doc improvements --- src/sage/combinat/designs/evenly_distributed_sets.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index d40faf84675..de47de019b6 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -69,7 +69,8 @@ cdef class EvenlyDistributedSetsBacktracker: - ``up_to_isomorphism`` - (boolean, default ``True``) whether only consider evenly distributed sets up to automorphisms of the field of the form - `x \mapsto ax + b`. + `x \mapsto ax + b`. If set to ``False`` then the iteration is over all + evenly distributed sets that contain ``0`` and ``1``. - ``check`` -- boolean (default is ``False``). Whether you want to check intermediate steps of the iterator. This is mainly intended for debugging @@ -167,7 +168,7 @@ cdef class EvenlyDistributedSetsBacktracker: # DYNAMIC DATA cdef unsigned int * B # current stack of elements of {0,...,q-1} cdef unsigned int * cosets # e array: cosets of differences of elts in B - cdef unsigned int * t # temporary variable for updates + cdef unsigned int * t # e array: temporary variable for updates def __dealloc__(self): if self.diff != NULL: From 007b862b6a8576c9e3127d9e6a4ed1df58d43e2f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 27 Apr 2015 17:50:36 +0200 Subject: [PATCH 580/665] trac #17662: Review --- src/sage/combinat/designs/database.py | 1 - .../combinat/designs/difference_family.py | 2 - .../designs/evenly_distributed_sets.pyx | 38 ++++++++++--------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 768c3f8877a..4a0ce366342 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -4138,7 +4138,6 @@ def RBIBD_120_8_1(): # 4, 5,..., 10. For each k in {4,...,10} the keys of EDS[k] are the prime powers # `q` so that `q = 1 modulo k(k-1)`. # The value at position EDS[k][q] is one of: -# - ``False`` if there is no `(q,k)`-evenly distributed set # - ``(None, B)`` if `q` is prime and `B` is an evenly distributed set in Z/pZ # - ``(poly, B)`` if `q=p^k` is a prime power (but not a prime). The # polynomial ``poly`` is such that GF(p)[x] / (poly) is a finite field of diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 865e369ea84..8f2881901f6 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -1194,8 +1194,6 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch sage: for k in EDS: ....: for v in EDS[k]: - ....: if EDS[k][v] is False: - ....: continue ....: assert designs.difference_family(v,k,1,existence=True) is True ....: df = designs.difference_family(v,k,1,check=True) diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index de47de019b6..307dc5586bd 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -516,7 +516,7 @@ cdef class EvenlyDistributedSetsBacktracker: if x < m or x >= q_m_1: raise RuntimeError("got x < m or x > q_m_1 (x={})".format(x)) if self.cosets[x/m]: - raise RuntimeError("got x={} in an already occuppied coset".format(x)) + raise RuntimeError("got x={} in an already occupied coset".format(x)) # try to append x B[kk] = x @@ -596,17 +596,20 @@ cdef class EvenlyDistributedSetsBacktracker: # 1. that the newly created differences x-B[i] will not be in a coset # already occuppied # - # 2. that applying some automorphisms we will not get an - # element smaller than B[2]. We should test all linear functions that - # send a subset of the form {x, B[i], B[j]} to {0, 1, z}. - # Given one such function, the values of the other functions can be - # easily deduced: the value different from 0/1 are 1/z, 1-z, - # 1/(1-z), (z-1)/z and z/(z-1). The attribute 'min_orbit[z]' is - # exactly the minimum among these values. - # So it is enough to test one of these functions. We choose - # t -> (x - t)/ (x - B[j]) - # (that maps x to 0 and B[j] to 1). Its value at B[i] is just - # z = (x - B[i]) / (x - B[j]). + # 2. that by applying some automorphisms we will not get an + # element smaller than B[2]. + # + # We should test all linear functions that send a subset of the form + # {x, B[i], B[j]} to some {0, 1, ?}. + # + # Note that if {x, B[i], B[j]} can be mapped to {0, 1, z} by some + # function, then it can also be mapped to all {0, 1, z'} where z'= + # 1/z, 1-z, 1/(1-z), (z-1)/z and z/(z-1). The attribute + # 'min_orbit[z]' is exactly the minimum among these values. + # + # So, it is enough to test one of these functions. We choose t -> (x + # - t)/ (x - B[j]) (that maps x to 0 and B[j] to 1). Its value at + # B[i] is just z = (x - B[i]) / (x - B[j]). # # In the special case when kk=2, or equivalently when we are testing if x # fits as a new B[2], then we just check that x is the minimum among @@ -619,13 +622,13 @@ cdef class EvenlyDistributedSetsBacktracker: for i in range(2,kk): x_m_i = diff[x][B[i]] - # check that the difference x-B[i] was not already in an - # occuppied coset + # 1. check that the difference x-B[i] was not already in an + # occuppied coset if self.cosets[x_m_i / m]: self.cosets[x / m] = 0 return 0 - # check relabeling + # 2. check relabeling for j in range(i): x_m_j = diff[x][B[j]] if self.min_orb[self.ratio[x_m_i][x_m_j]] < B[2]: @@ -643,6 +646,7 @@ cdef class EvenlyDistributedSetsBacktracker: self.t, self.cosets = self.cosets, self.t return 1 + @cython.cdivision(True) cdef int _check_cosets(self, unsigned int kk) except -1: r""" Sanity check (only for debug purposes). @@ -655,8 +659,8 @@ cdef class EvenlyDistributedSetsBacktracker: c = 0 for i in range(self.e): c += self.cosets[i] - if c != kk * (kk-1) / 2: - raise RuntimeError("the number of elements in cosets is wrong! Got {} instead of {}.".format(c, kk*(kk-1))) + if c != (kk * (kk-1)) / 2: + raise RuntimeError("the number of elements in cosets is wrong! Got {} instead of {}.".format(c, (kk*(kk-1))/2)) for i in range(kk): for j in range(i): From 8eaa4612f9d59837e7ce84e2e3cd44be0d49b939 Mon Sep 17 00:00:00 2001 From: Leif Leonhardy Date: Mon, 27 Apr 2015 19:17:39 +0200 Subject: [PATCH 581/665] Add patch to let Lcalc build with GCC 5.x (C++ issue, #18316) "(forbidden) default parameters, part II" (in function *definitions*) -- again a small subset of the changes necessary to let Lcalc build with Clang (cf. #12437). --- .../lcalc-1.23_default_parameters_2.patch | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 build/pkgs/lcalc/patches/lcalc-1.23_default_parameters_2.patch diff --git a/build/pkgs/lcalc/patches/lcalc-1.23_default_parameters_2.patch b/build/pkgs/lcalc/patches/lcalc-1.23_default_parameters_2.patch new file mode 100644 index 00000000000..f5fd45358d0 --- /dev/null +++ b/build/pkgs/lcalc/patches/lcalc-1.23_default_parameters_2.patch @@ -0,0 +1,56 @@ +--- lcalc-1.23/include/Lgamma.h 2012-08-08 23:21:55.000000000 +0200 ++++ lcalc-1.23/include/Lgamma.h 2014-05-18 21:15:27.786889718 +0200 +@@ -77,7 +77,7 @@ + //n=0 should just give log_GAMMA(z)... thus making log_GAMMA + //code obsolete. But leave log_GAMMA intact anyways. + template +-precise(ttype) log_GAMMA (ttype z,int n=0) ++precise(ttype) log_GAMMA (ttype z,int n) + { + int M; + precise(ttype) log_G,r,r2,y; +@@ -230,7 +230,7 @@ + //value exp_w which holds exp(-w) + //computes G(z,w), so there's an extra w^(-z) factor. + template +-Complex inc_GAMMA (ttype z,ttype w, const char *method="temme", ttype exp_w = 0, bool recycle=false) ++Complex inc_GAMMA (ttype z,ttype w, const char *method, ttype exp_w, bool recycle) + { + + Complex G; +@@ -334,7 +334,7 @@ + + + template +-ttype cfrac_GAMMA (ttype z,ttype w, ttype exp_w=0, bool recycle=false) //computes G(z,w) via continued fraction ++ttype cfrac_GAMMA (ttype z,ttype w, ttype exp_w, bool recycle) //computes G(z,w) via continued fraction + { + + ttype G; +@@ -424,7 +424,7 @@ + } + + template +-ttype asympt_GAMMA (ttype z,ttype w, ttype exp_w = 0, bool recycle=false) //computes G(z,w) via asymptotic series ++ttype asympt_GAMMA (ttype z,ttype w, ttype exp_w, bool recycle) //computes G(z,w) via asymptotic series + { + + if(my_verbose>3) cout << "called asympt_GAMMA("< +-ttype comp_inc_GAMMA (ttype z,ttype w,ttype exp_w = 0, bool recycle=false) //computes g(z,w) ++ttype comp_inc_GAMMA (ttype z,ttype w,ttype exp_w, bool recycle) //computes g(z,w) + { + + ttype g; +@@ -604,7 +604,7 @@ + } + + template +-Complex gamma_sum(Complex s, int what_type, ttype *coeff, int N, Double g, Complex l, Double Q, Long Period, Complex delta=1, const char *method="temme") ++Complex gamma_sum(Complex s, int what_type, ttype *coeff, int N, Double g, Complex l, Double Q, Long Period, Complex delta, const char *method) + { + Complex SUM=0; + From 39273f1aacfdd307d20b729ae732e349438a8422 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 27 Apr 2015 20:07:44 +0200 Subject: [PATCH 582/665] Fix doctest formatting --- src/sage/structure/element.pyx | 120 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index eee01f21e0b..69811352442 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -1128,68 +1128,68 @@ cdef class ElementWithCachedMethod(Element): :: sage: cython_code = ["from sage.structure.element cimport Element, ElementWithCachedMethod", - ... "cdef class MyBrokenElement(Element):", - ... " cdef public object x", - ... " def __init__(self,P,x):", - ... " self.x=x", - ... " Element.__init__(self,P)", - ... " def __neg__(self):", - ... " return MyBrokenElement(self.parent(),-self.x)", - ... " def _repr_(self):", - ... " return '<%s>'%self.x", - ... " def __hash__(self):", - ... " return hash(self.x)", - ... " def __cmp__(left, right):", - ... " return (left)._cmp(right)", - ... " def __richcmp__(left, right, op):", - ... " return (left)._richcmp(right,op)", - ... " cpdef int _cmp_(left, Element right) except -2:", - ... " return cmp(left.x,right.x)", - ... " def raw_test(self):", - ... " return -self", - ... "cdef class MyElement(ElementWithCachedMethod):", - ... " cdef public object x", - ... " def __init__(self,P,x):", - ... " self.x=x", - ... " Element.__init__(self,P)", - ... " def __neg__(self):", - ... " return MyElement(self.parent(),-self.x)", - ... " def _repr_(self):", - ... " return '<%s>'%self.x", - ... " def __hash__(self):", - ... " return hash(self.x)", - ... " def __cmp__(left, right):", - ... " return (left)._cmp(right)", - ... " def __richcmp__(left, right, op):", - ... " return (left)._richcmp(right,op)", - ... " cpdef int _cmp_(left, Element right) except -2:", - ... " return cmp(left.x,right.x)", - ... " def raw_test(self):", - ... " return -self", - ... "class MyPythonElement(MyBrokenElement): pass", - ... "from sage.structure.parent cimport Parent", - ... "cdef class MyParent(Parent):", - ... " Element = MyElement"] + ....: "cdef class MyBrokenElement(Element):", + ....: " cdef public object x", + ....: " def __init__(self,P,x):", + ....: " self.x=x", + ....: " Element.__init__(self,P)", + ....: " def __neg__(self):", + ....: " return MyBrokenElement(self.parent(),-self.x)", + ....: " def _repr_(self):", + ....: " return '<%s>'%self.x", + ....: " def __hash__(self):", + ....: " return hash(self.x)", + ....: " def __cmp__(left, right):", + ....: " return (left)._cmp(right)", + ....: " def __richcmp__(left, right, op):", + ....: " return (left)._richcmp(right,op)", + ....: " cpdef int _cmp_(left, Element right) except -2:", + ....: " return cmp(left.x,right.x)", + ....: " def raw_test(self):", + ....: " return -self", + ....: "cdef class MyElement(ElementWithCachedMethod):", + ....: " cdef public object x", + ....: " def __init__(self,P,x):", + ....: " self.x=x", + ....: " Element.__init__(self,P)", + ....: " def __neg__(self):", + ....: " return MyElement(self.parent(),-self.x)", + ....: " def _repr_(self):", + ....: " return '<%s>'%self.x", + ....: " def __hash__(self):", + ....: " return hash(self.x)", + ....: " def __cmp__(left, right):", + ....: " return (left)._cmp(right)", + ....: " def __richcmp__(left, right, op):", + ....: " return (left)._richcmp(right,op)", + ....: " cpdef int _cmp_(left, Element right) except -2:", + ....: " return cmp(left.x,right.x)", + ....: " def raw_test(self):", + ....: " return -self", + ....: "class MyPythonElement(MyBrokenElement): pass", + ....: "from sage.structure.parent cimport Parent", + ....: "cdef class MyParent(Parent):", + ....: " Element = MyElement"] sage: cython('\n'.join(cython_code)) sage: cython_code = ["from sage.all import cached_method, cached_in_parent_method, Category, Objects", - ... "class MyCategory(Category):", - ... " @cached_method", - ... " def super_categories(self):", - ... " return [Objects()]", - ... " class ElementMethods:", - ... " @cached_method", - ... " def element_cache_test(self):", - ... " return -self", - ... " @cached_in_parent_method", - ... " def element_via_parent_test(self):", - ... " return -self", - ... " class ParentMethods:", - ... " @cached_method", - ... " def one(self):", - ... " return self.element_class(self,1)", - ... " @cached_method", - ... " def invert(self, x):", - ... " return -x"] + ....: "class MyCategory(Category):", + ....: " @cached_method", + ....: " def super_categories(self):", + ....: " return [Objects()]", + ....: " class ElementMethods:", + ....: " @cached_method", + ....: " def element_cache_test(self):", + ....: " return -self", + ....: " @cached_in_parent_method", + ....: " def element_via_parent_test(self):", + ....: " return -self", + ....: " class ParentMethods:", + ....: " @cached_method", + ....: " def one(self):", + ....: " return self.element_class(self,1)", + ....: " @cached_method", + ....: " def invert(self, x):", + ....: " return -x"] sage: cython('\n'.join(cython_code)) sage: C = MyCategory() sage: P = MyParent(category=C) From 04570b3dfd194fea8c2437c8717c3dfb8704b4af Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 27 Apr 2015 20:41:09 +0200 Subject: [PATCH 583/665] Fix bad doctest in etaproducts --- src/sage/modular/etaproducts.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index 0a2edc71539..27ddea76497 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -443,22 +443,22 @@ def _div_(self, other): def __cmp__(self, other): r""" - Compare self to other. Eta products compare first according to - their levels, then according to their rdicts. + Compare self to other. Eta products are compared according to + their rdicts. EXAMPLES:: sage: EtaProduct(2, {2:24,1:-24}) == 1 False - sage: EtaProduct(2, {2:24, 1:-24}) < EtaProduct(4, {2:24, 1:-24}) + sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:-24, 2:24}) True - sage: EtaProduct(2, {2:24, 1:-24}) == EtaProduct(4, {2:24, 1:-24}) + sage: EtaProduct(6, {1:-24, 2:24}) == EtaProduct(6, {1:24, 2:-24}) False - sage: EtaProduct(2, {2:24, 1:-24}) < EtaProduct(4, {2:48, 1:-48}) + sage: EtaProduct(6, {1:-24, 2:24}) < EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24}) True + sage: EtaProduct(6, {1:-24, 2:24, 3:24, 6:-24}) < EtaProduct(6, {1:-24, 2:24}) + False """ - if not isinstance(other, EtaGroupElement): - return cmp(type(self), type(other)) return (cmp(self.level(), other.level()) or cmp(self._rdict, other._rdict)) def _short_repr(self): From 8d61e569bfd222ee604bf433bf557ac88469518c Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 27 Apr 2015 21:36:19 +0200 Subject: [PATCH 584/665] trac #18317: General documentation about graph data structures --- src/doc/en/reference/graphs/index.rst | 1 + src/sage/graphs/base/c_graph.pyx | 4 +- src/sage/graphs/base/dense_graph.pyx | 3 + src/sage/graphs/base/graph_backends.py | 51 ++++++++++- src/sage/graphs/base/overview.py | 88 +++++++++++++++++++ src/sage/graphs/base/sparse_graph.pyx | 3 + src/sage/graphs/base/static_dense_graph.pyx | 3 + .../graphs/base/static_sparse_backend.pyx | 3 + src/sage/graphs/base/static_sparse_graph.pyx | 8 +- src/sage/graphs/digraph.py | 6 +- src/sage/graphs/graph.py | 3 +- 11 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 src/sage/graphs/base/overview.py diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index 4edcaf46ec3..a1fc1c3e9b4 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -35,6 +35,7 @@ Low-level implementation .. toctree:: :maxdepth: 1 + sage/graphs/base/overview sage/graphs/base/c_graph sage/graphs/base/sparse_graph sage/graphs/base/dense_graph diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index c9447e1fb36..ce446cb843a 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1,4 +1,4 @@ -""" +r""" Fast compiled graphs This is a Cython implementation of the base class for sparse and dense graphs @@ -7,6 +7,8 @@ extend this base class and implement missing functionalities. Whenever possible, specific methods should also be overridden with implementations that suit the graph type under consideration. +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. Data structure -------------- diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index 7827e40fef8..212acffb5cf 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -1,6 +1,9 @@ r""" Fast dense graphs +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. + Usage Introduction ------------------ diff --git a/src/sage/graphs/base/graph_backends.py b/src/sage/graphs/base/graph_backends.py index e186b925c2d..28da660d1a2 100644 --- a/src/sage/graphs/base/graph_backends.py +++ b/src/sage/graphs/base/graph_backends.py @@ -1,6 +1,51 @@ -""" -Implements various backends for Sage graphs. - +r""" +Backends for Sage (di)graphs. + +This module implements :class:`GenericGraphBackend` (the base class for +backends) and :class:`NetworkXGraphBackend` (a wrapper for `NetworkX +`__ graphs) + +Any graph backend must redefine the following methods (for which +:class:`GenericGraphBackend` raises a ``NotImplementedError``) + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`~GenericGraphBackend.add_edge` | Add an edge `(u,v)` to ``self``, with label `l`. + :meth:`~GenericGraphBackend.add_edges` | Add a sequence of edges to ``self``. + :meth:`~GenericGraphBackend.add_vertex` | Add a labelled vertex to ``self``. + :meth:`~GenericGraphBackend.add_vertices` | Add labelled vertices to ``self``. + :meth:`~GenericGraphBackend.degree` | Returns the total number of vertices incident to v. + :meth:`~GenericGraphBackend.in_degree` | Return the in-degree of `v` + :meth:`~GenericGraphBackend.out_degree` | Return the out-degree of `v` + :meth:`~GenericGraphBackend.del_edge` | Deletes the edge `(u,v)` with label `l`. + :meth:`~GenericGraphBackend.del_vertex` | Delete a labelled vertex in ``self``. + :meth:`~GenericGraphBackend.del_vertices` | Delete labelled vertices in ``self``. + :meth:`~GenericGraphBackend.get_edge_label` | Returns the edge label of `(u,v)`. + :meth:`~GenericGraphBackend.has_edge` | True if ``self`` has an edge `(u,v)` with label `l`. + :meth:`~GenericGraphBackend.has_vertex` | True if ``self`` has a vertex with label `v`. + :meth:`~GenericGraphBackend.iterator_edges` | Iterate over the edges incident to a sequence of vertices. + :meth:`~GenericGraphBackend.iterator_in_edges` | Iterate over the incoming edges incident to a sequence of vertices. + :meth:`~GenericGraphBackend.iterator_out_edges` | Iterate over the outbound edges incident to a sequence of vertices. + :meth:`~GenericGraphBackend.iterator_nbrs` | Iterate over the vertices adjacent to `v`. + :meth:`~GenericGraphBackend.iterator_in_nbrs` | Iterate over the vertices u such that the edge `(u,v)` is in ``self`` (that is, predecessors of `v`). + :meth:`~GenericGraphBackend.iterator_out_nbrs` | Iterate over the vertices u such that the edge `(v,u)` is in ``self`` (that is, successors of `v`). + :meth:`~GenericGraphBackend.iterator_verts` | Iterate over the vertices `v` with labels in verts. + :meth:`~GenericGraphBackend.loops` | Get/set whether or not ``self`` allows loops. + :meth:`~GenericGraphBackend.multiple_edges` | Get/set whether or not ``self`` allows multiple edges. + :meth:`~GenericGraphBackend.name` | Get/set name of ``self``. + :meth:`~GenericGraphBackend.num_edges` | The number of edges in ``self`` + :meth:`~GenericGraphBackend.num_verts` | The number of vertices in ``self`` + :meth:`~GenericGraphBackend.relabel` | Relabel the vertices of ``self`` by a permutation. + :meth:`~GenericGraphBackend.set_edge_label` | Label the edge `(u,v)` by `l`. + +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. + +Classes and methods +------------------- """ #******************************************************************************* diff --git a/src/sage/graphs/base/overview.py b/src/sage/graphs/base/overview.py new file mode 100644 index 00000000000..766abc7cc73 --- /dev/null +++ b/src/sage/graphs/base/overview.py @@ -0,0 +1,88 @@ +r""" +Overview of (di)graph data structures + +This module contains no code, and describes Sage's data structures for graphs +and digraphs. They can be used directly at Cython/C level, or through the +:class:`Graph` and :class:`DiGraph` classes (except one) + +Data structures +--------------- + +Four data structures are natively available for graphs in Sage: + +- :mod:`~sage.graphs.base.sparse_graph` (default) -- for sparse graphs, with a + `\log(n)` edge test, and easy enumeration of neighbors. It is the most + general-purpose data structure, though it can have a high memory cost in + practice. + + - Supports: Addition/removal of edges/vertices, multiple edges, edge labels + and loops. + +- :mod:`~sage.graphs.base.dense_graph` -- for dense graphs, with a `O(1)` edge + test, and slow enumeration of neighbors. + + - Supports: addition/removal of edges/vertices available, and loops. + - Does not support: multiple edges and edge labels. + +- :mod:`~sage.graphs.base.static_sparse_graph` -- for sparse graphs and very + intensive computations (at C-level). It is faster than + :mod:`~sage.graphs.base.sparse_graph` in practice and *much* ligther in + memory. + + - Supports: multiple edges, edge labels and loops + - Does not support: addition/removal of edges/vertices. + +- :mod:`~sage.graphs.base.static_dense_graph` -- for dense graphs and very + intensive computations (at C-level). It is mostly a wrapper over bitsets. + + - Supports: addition/removal of edges/vertices available, and loops. + - Does not support: multiple edges and edge labels. + +For more information, see the data structures' respective pages. + +The backends +------------ + +The :class:`Graph` and :class:`DiGraph` objects delegate the storage of vertices +and edges to other objects: the :mod:`graph backends +`:: + + sage: Graph()._backend + + +A graph backend is a simpler (di)graph class having only the most elementary +methods (e.g.: add/remove vertices/edges). Its vertices can be arbitrary +hashable objects. + +The backends defined in Sage are: + +- :class:`~sage.graphs.base.c_graph.CGraphBackend` (default) + +- :class:`~sage.graphs.base.graph_backends.NetworkXGraphBackend` (a wrapper for + `NetworkX `__ graphs) + +CGraph and CGraphBackend +------------------------ + +:class:`~sage.graphs.base.c_graph.CGraphBackend` is the backend of all native +data structures that can be used by :class:`Graph` and :class:`DiGraph`. It is +extended by: + +- :class:`~sage.graphs.base.dense_graph.DenseGraphBackend` +- :class:`~sage.graphs.base.sparse_graph.SparseGraphBackend` +- :class:`~sage.graphs.base.static_sparse_backend.StaticSparseBackend` + +While a :class:`~sage.graphs.base.c_graph.CGraphBackend` deals with arbitrary +(hashable) vertices, it contains a ``._cg`` attribute of type +:class:`~sage.graphs.base.c_graph.CGraph` which only deals with integer +vertices. + +The :class:`~sage.graphs.base.c_graph.CGraph` data structures available in Sage +are: + +- :class:`~sage.graphs.base.dense_graph.DenseGraph` +- :class:`~sage.graphs.base.sparse_graph.SparseGraph` +- :class:`~sage.graphs.base.static_sparse_backend.StaticSparseCGraph` + +See the :mod:`~sage.graphs.base.c_graph` module for more information. +""" diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 6bd4d3d0ded..ba1a87fe855 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1,6 +1,9 @@ r""" Fast sparse graphs +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. + Usage Introduction ------------------ diff --git a/src/sage/graphs/base/static_dense_graph.pyx b/src/sage/graphs/base/static_dense_graph.pyx index 09058c44856..a364f045390 100644 --- a/src/sage/graphs/base/static_dense_graph.pyx +++ b/src/sage/graphs/base/static_dense_graph.pyx @@ -16,6 +16,9 @@ It is all based on the binary matrix data structure described in structure. The only difference is that it differentiates the rows (the vertices) instead of storing the whole data in a long bitset, and we can use that. +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. + Index ----- diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 7eed8a2eaac..2ae8cdee0f3 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -11,6 +11,9 @@ you need to list the graph's edge, or those incident to a vertex, but an adjacency test can be much longer than in a dense data structure (i.e. like in :mod:`sage.graphs.base.static_dense_graph`) +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. + Two classes ----------- diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 915bb2265de..13dc3b4053d 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -13,9 +13,11 @@ for graph algorithms whose main operation is to *list the out-neighbours of a vertex* (which is precisely what BFS, DFS, distance computations and the flow-related stuff waste their life on). -The code contained in this module is written C-style. While Sage needs a class -for static graphs (not available today, i.e. 2012-01-13) it is not what we try -to address here. The purpose is efficiency and simplicity. +The code contained in this module is written C-style. The purpose is efficiency +and simplicity. + +For an overview of graph data structures in sage, see +:mod:`~sage.graphs.base.overview`. Author: diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index f7749d256e4..43dd1ce5b1b 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -119,8 +119,7 @@ class DiGraph(GenericGraph): - """ - Directed graph. + """Directed graph. A digraph or directed graph is a set of vertices connected by oriented edges. For more information, see the @@ -264,7 +263,8 @@ class DiGraph(GenericGraph): ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. - - ``data_structure`` -- one of the following + - ``data_structure`` -- one of the following (for more information, see + :mod:`~sage.graphs.base.overview`): * ``"dense"`` -- selects the :mod:`~sage.graphs.base.dense_graph` backend. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 881dbfbd1fd..4cb75896ed8 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -692,7 +692,8 @@ class Graph(GenericGraph): ``data_structure="sparse"``, and ``sparse=False`` is an alias for ``data_structure="dense"``. - - ``data_structure`` -- one of the following + - ``data_structure`` -- one of the following (for more information, see + :mod:`~sage.graphs.base.overview`) * ``"dense"`` -- selects the :mod:`~sage.graphs.base.dense_graph` backend. From b7d90367738afb7bfcf2d97701451fccbeebf31f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 27 Apr 2015 22:33:05 +0200 Subject: [PATCH 585/665] trac #18317: Reviewer's comments --- src/sage/graphs/base/overview.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/base/overview.py b/src/sage/graphs/base/overview.py index 766abc7cc73..40028a9b62d 100644 --- a/src/sage/graphs/base/overview.py +++ b/src/sage/graphs/base/overview.py @@ -8,34 +8,34 @@ Data structures --------------- -Four data structures are natively available for graphs in Sage: +Four data structures are natively available for (di)graphs in Sage: -- :mod:`~sage.graphs.base.sparse_graph` (default) -- for sparse graphs, with a - `\log(n)` edge test, and easy enumeration of neighbors. It is the most +- :mod:`~sage.graphs.base.sparse_graph` (default) -- for sparse (di)graphs, with + a `\log(n)` edge test, and easy enumeration of neighbors. It is the most general-purpose data structure, though it can have a high memory cost in practice. - Supports: Addition/removal of edges/vertices, multiple edges, edge labels and loops. -- :mod:`~sage.graphs.base.dense_graph` -- for dense graphs, with a `O(1)` edge - test, and slow enumeration of neighbors. +- :mod:`~sage.graphs.base.dense_graph` -- for dense (di)graphs, with a `O(1)` + edge test, and slow enumeration of neighbors. - - Supports: addition/removal of edges/vertices available, and loops. + - Supports: addition/removal of edges/vertices, and loops. - Does not support: multiple edges and edge labels. -- :mod:`~sage.graphs.base.static_sparse_graph` -- for sparse graphs and very +- :mod:`~sage.graphs.base.static_sparse_graph` -- for sparse (di)graphs and very intensive computations (at C-level). It is faster than - :mod:`~sage.graphs.base.sparse_graph` in practice and *much* ligther in + :mod:`~sage.graphs.base.sparse_graph` in practice and *much* lighter in memory. - Supports: multiple edges, edge labels and loops - Does not support: addition/removal of edges/vertices. -- :mod:`~sage.graphs.base.static_dense_graph` -- for dense graphs and very +- :mod:`~sage.graphs.base.static_dense_graph` -- for dense (di)graphs and very intensive computations (at C-level). It is mostly a wrapper over bitsets. - - Supports: addition/removal of edges/vertices available, and loops. + - Supports: addition/removal of edges/vertices, and loops. - Does not support: multiple edges and edge labels. For more information, see the data structures' respective pages. @@ -50,7 +50,7 @@ sage: Graph()._backend -A graph backend is a simpler (di)graph class having only the most elementary +A (di)graph backend is a simpler (di)graph class having only the most elementary methods (e.g.: add/remove vertices/edges). Its vertices can be arbitrary hashable objects. From 256df27b7063df421aea65472a8a1816f9956661 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 27 Apr 2015 23:48:24 +0200 Subject: [PATCH 586/665] Trac 17543: reviewer comments --- src/sage/modular/abvar/finite_subgroup.py | 18 ++---------------- src/sage/structure/gens_py.py | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index e92ff366fe9..ae3e819b485 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -640,7 +640,7 @@ def _element_constructor_(self, x, check=True): sage: G(J.torsion_subgroup(3).0) Traceback (most recent call last): ... - TypeError: x does not define an element of self + TypeError: cannot convert (1/3, 0, 0, 0) into Finite subgroup with invariants [11, 11, 11, 11] over QQ of Abelian variety J0(23) of dimension 2 """ if isinstance(x, TorsionPoint): if x.parent() == self: @@ -651,7 +651,7 @@ def _element_constructor_(self, x, check=True): z = self.abelian_variety().vector_space()(x, check=check) if z in self.lattice(): return self.element_class(self, z, check=False) - raise TypeError("x does not define an element of self") + raise TypeError("cannot convert {!r} into {}".format(x, self)) def __contains__(self, x): @@ -787,20 +787,6 @@ def invariants(self): self.__invariants = I return I - def generator_orders(self): - """ - Return the orders of the chosen generators of ``self``. - - EXAMPLES:: - - sage: G = J0(24).cuspidal_subgroup() - sage: G.gens() - [[(1/4, 0)], [(0, 1/2)]] - sage: G.generator_orders() - [4, 2] - """ - return [x.additive_order() for x in self.gens()] - __iter__ = abelian_iterator diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index c2725033115..e22a8a28ffe 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -52,7 +52,7 @@ def abelian_iterator(M): yield M(0) return - stop = list(M.generator_orders()) + stop = [g.additive_order() for g in G] for i in range(len(stop)): if stop[i] is infinity: raise ArithmeticError("%s is not finite."%M) From dddef7fb2eb10c0ba472ee7087d33dd49c4e7acc Mon Sep 17 00:00:00 2001 From: Leif Leonhardy Date: Tue, 28 Apr 2015 03:32:41 +0200 Subject: [PATCH 587/665] Bump patch level of Lcalc package (to 1.23.p14; #18316) --- build/pkgs/lcalc/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/lcalc/package-version.txt b/build/pkgs/lcalc/package-version.txt index e8d6b90a1d2..f57d826d2bd 100644 --- a/build/pkgs/lcalc/package-version.txt +++ b/build/pkgs/lcalc/package-version.txt @@ -1 +1 @@ -1.23.p13 +1.23.p14 From e55e3153cd87e9e8cc63acfd34af7681718bbafc Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 28 Apr 2015 00:45:29 -0400 Subject: [PATCH 588/665] Updated Sage version to 6.7.beta3 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 2 +- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index c76ad65caad..f0da0df6c91 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.7.beta2, released 2015-04-21 +Sage version 6.7.beta3, released 2015-04-28 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 324c8f4955b..988f1ba2eec 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=cfa4d6a576b31399a5a7c95e5ca7eaafd7bc79fd -md5=6f1978763cfa1d7534a2bf64be00d390 -cksum=1608967615 +sha1=d0a00ec9d7e49ef6e758aee29f60cd399b2a8ff9 +md5=cbf68f077445ecb657e52276762d7e44 +cksum=3915828491 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index d22307c427b..8643cf6deba 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -88 +89 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index 0e51a90491a..e3d6f783189 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.7.beta2, Release Date: 2015-04-21 │ +│ SageMath Version 6.7.beta3, Release Date: 2015-04-28 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 34bdaebad59..c352e438a0c 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='6.7.beta2' -SAGE_RELEASE_DATE='2015-04-21' +SAGE_VERSION='6.7.beta3' +SAGE_RELEASE_DATE='2015-04-28' diff --git a/src/sage/version.py b/src/sage/version.py index cf52bc2b13a..a4170d89280 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '6.7.beta2' -date = '2015-04-21' +version = '6.7.beta3' +date = '2015-04-28' From 3976f2cc4ec59c9f978d9d02c7f697c81025c4ef Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 28 Apr 2015 10:19:44 +0200 Subject: [PATCH 589/665] Add pointers for special uses of __richcmp__ --- src/sage/structure/element.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 69811352442..8ec374928ef 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -948,6 +948,13 @@ cdef class Element(SageObject): If a class wants to implement rich comparison without coercion, then ``_richcmp`` should be defined (as well as ``__richcmp__`` as usual). + See :class:`sage.numerical.linear_functions.LinearConstraint` + for such an example. + + For efficiency reasons, a class can do certain "manual" + coercions directly in ``__richcmp__``, using ``_richcmp`` + for the remaining cases. This is done for example in + :class:`Integer`. """ if have_same_parent_c(self, other): # Same parents, in particular other must be an Element too. From 9205d8894938dd1381ca2e47aae750d4843a3db5 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Tue, 28 Apr 2015 10:34:29 +0100 Subject: [PATCH 590/665] Fix memleak: cryptoMiniSat was never freed --- src/sage/sat/solvers/cryptominisat/cryptominisat.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/sat/solvers/cryptominisat/cryptominisat.pyx b/src/sage/sat/solvers/cryptominisat/cryptominisat.pyx index c93a3bdf41f..919506bcd96 100644 --- a/src/sage/sat/solvers/cryptominisat/cryptominisat.pyx +++ b/src/sage/sat/solvers/cryptominisat/cryptominisat.pyx @@ -112,7 +112,7 @@ cdef class CryptoMiniSat(SatSolver): sage: cms = CryptoMiniSat() # optional - cryptominisat sage: del cms # optional - cryptominisat """ - del self + del self._solver def __repr__(self): """ From 1e0956157ef8f49bc19eb145dc60589f8e59587a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 28 Apr 2015 12:44:26 +0200 Subject: [PATCH 591/665] Trac 16880: optimization + Pari -> PARI --- src/sage/rings/arith.py | 2 +- src/sage/rings/integer.pyx | 65 ++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/arith.py b/src/sage/rings/arith.py index ff083a0ea02..2a5024a56de 100644 --- a/src/sage/rings/arith.py +++ b/src/sage/rings/arith.py @@ -1144,7 +1144,7 @@ def previous_prime_power(n): sage: 127.previous_prime_power() 125 - Input lesser or equal than `2` raises errors:: + Input less than or equal to `2` raises errors:: sage: previous_prime_power(2) Traceback (most recent call last): diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index c65445ac43b..39f8d26a9ff 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -5095,7 +5095,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): r""" Return the next prime after self. - This method calls the Pari ``nextprime`` function. + This method calls the PARI ``nextprime`` function. INPUT: @@ -5134,7 +5134,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): r""" Returns the previous prime before self. - This method calls the Pari ``precprime`` function. + This method calls the PARI ``precprime`` function. INPUT: @@ -5214,30 +5214,39 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 109 sage: 2044.next_prime_power() 2048 + + TESTS:: + + sage: [(2**k-1).next_prime_power() for k in range(1,10)] + [2, 4, 8, 16, 32, 64, 128, 256, 512] + sage: [(2**k).next_prime_power() for k in range(10)] + [2, 3, 5, 9, 17, 37, 67, 131, 257, 521] + + sage: l0 = [ZZ.random_element(3,1000).previous_prime_power() for _ in range(10)] + sage: l1 = [n.next_prime_power().previous_prime_power() for n in l0] + sage: l0 == l1 + True """ cdef Integer n = PY_NEW(Integer) - mpz_set(n.value, self.value) - if mpz_cmp_ui(n.value, 2) < 0: - mpz_set_ui(n.value, 2) - return n + mpz_add_ui(n.value, self.value, 1) + if mpz_cmp_ui(n.value, 2) <= 0: + return smallInteger(2) - mpz_add_ui(n.value, n.value, 1) if mpz_even_p(n.value): if n.is_prime_power(proof=proof): return n mpz_add_ui(n.value, n.value, 1) - # the next power of 2 - cdef Integer m = PY_NEW(Integer) - mpz_set_ui(m.value, 1) - mpz_mul_2exp(m.value, m.value, mpz_sizeinbase(n.value,2)) - - while mpz_cmp(m.value, n.value) == 1: + cdef mp_bitcnt_t bit_index = mpz_sizeinbase(n.value,2) + while not mpz_tstbit(n.value, bit_index): if n.is_prime_power(proof=proof): return n mpz_add_ui(n.value, n.value, 2) - return m + + # return the power of 2 we just skept + mpz_sub_ui(n.value, n.value, 1) + return n def previous_prime_power(self, proof=None): r""" @@ -5278,29 +5287,39 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Traceback (most recent call last): ... ValueError: no prime power less than 2 + + TESTS:: + + sage: [(2**k+1).previous_prime_power() for k in range(1,10)] + [2, 4, 8, 16, 32, 64, 128, 256, 512] + sage: [(2**k).previous_prime_power() for k in range(2, 10)] + [3, 7, 13, 31, 61, 127, 251, 509] + + sage: l0 = [ZZ.random_element(3,1000).next_prime_power() for _ in range(10)] + sage: l1 = [n.previous_prime_power().next_prime_power() for n in l0] + sage: l0 == l1 + True """ if mpz_cmp_ui(self.value, 2) <= 0: raise ValueError("no prime power less than 2") cdef Integer n = PY_NEW(Integer) - mpz_set(n.value, self.value) - mpz_sub_ui(n.value, n.value, 1) + mpz_sub_ui(n.value, self.value, 1) if mpz_even_p(n.value): if n.is_prime_power(proof=proof): return n mpz_sub_ui(n.value, n.value, 1) - # the previous power of 2 - cdef Integer m = PY_NEW(Integer) - mpz_set_ui(m.value, 1) - mpz_mul_2exp(m.value, m.value, mpz_sizeinbase(n.value,2)-1) - - while mpz_cmp(m.value, n.value) == -1: + cdef mp_bitcnt_t bit_index = mpz_sizeinbase(n.value,2)-1 + while mpz_tstbit(n.value, bit_index): if n.is_prime_power(proof=proof): return n mpz_sub_ui(n.value, n.value, 2) - return m + + # return the power of 2 we just skept + mpz_add_ui(n.value, n.value, 1) + return n def additive_order(self): """ From 35c0211766537e6769cd060ed528ad9d77e60068 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Tue, 28 Apr 2015 13:51:02 +0200 Subject: [PATCH 592/665] Trac 16880: optimization --- src/sage/rings/integer.pyx | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 39f8d26a9ff..96d099ce931 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -5222,29 +5222,25 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: [(2**k).next_prime_power() for k in range(10)] [2, 3, 5, 9, 17, 37, 67, 131, 257, 521] - sage: l0 = [ZZ.random_element(3,1000).previous_prime_power() for _ in range(10)] - sage: l1 = [n.next_prime_power().previous_prime_power() for n in l0] - sage: l0 == l1 - True + sage: for _ in range(10): + ....: n = ZZ.random_element(2**256).next_prime_power() + ....: m = n.next_prime_power().previous_prime_power() + ....: assert m == n, "problem with n = {}".format(n) """ - cdef Integer n = PY_NEW(Integer) - - mpz_add_ui(n.value, self.value, 1) - if mpz_cmp_ui(n.value, 2) <= 0: + if mpz_cmp_ui(self.value, 2) < 0: return smallInteger(2) - if mpz_even_p(n.value): - if n.is_prime_power(proof=proof): - return n - mpz_add_ui(n.value, n.value, 1) + cdef mp_bitcnt_t bit_index = mpz_sizeinbase(self.value,2) + cdef Integer n = PY_NEW(Integer) + + mpz_add_ui(n.value, self.value, 1 if mpz_even_p(self.value) else 2) - cdef mp_bitcnt_t bit_index = mpz_sizeinbase(n.value,2) while not mpz_tstbit(n.value, bit_index): if n.is_prime_power(proof=proof): return n mpz_add_ui(n.value, n.value, 2) - # return the power of 2 we just skept + # return the power of 2 we just skipped mpz_sub_ui(n.value, n.value, 1) return n @@ -5295,10 +5291,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: [(2**k).previous_prime_power() for k in range(2, 10)] [3, 7, 13, 31, 61, 127, 251, 509] - sage: l0 = [ZZ.random_element(3,1000).next_prime_power() for _ in range(10)] - sage: l1 = [n.previous_prime_power().next_prime_power() for n in l0] - sage: l0 == l1 - True + sage: for _ in range(10): + ....: n = ZZ.random_element(3,2**256).previous_prime_power() + ....: m = n.previous_prime_power().next_prime_power() + ....: assert m == n, "problem with n = {}".format(n) """ if mpz_cmp_ui(self.value, 2) <= 0: raise ValueError("no prime power less than 2") @@ -5306,18 +5302,16 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef Integer n = PY_NEW(Integer) mpz_sub_ui(n.value, self.value, 1) + cdef mp_bitcnt_t bit_index = mpz_sizeinbase(n.value,2)-1 if mpz_even_p(n.value): - if n.is_prime_power(proof=proof): - return n mpz_sub_ui(n.value, n.value, 1) - cdef mp_bitcnt_t bit_index = mpz_sizeinbase(n.value,2)-1 while mpz_tstbit(n.value, bit_index): if n.is_prime_power(proof=proof): return n mpz_sub_ui(n.value, n.value, 2) - # return the power of 2 we just skept + # return the power of 2 we just skipped mpz_add_ui(n.value, n.value, 1) return n From ddbf10189c1d49587e95ea410ce3dd6e3a3ecd3e Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 28 Apr 2015 14:05:49 +0200 Subject: [PATCH 593/665] Trac 17543: simplify FiniteSubgroup._element_constructor_() --- src/sage/modular/abvar/finite_subgroup.py | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index ae3e819b485..03b5dad950b 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -634,25 +634,26 @@ def _element_constructor_(self, x, check=True): sage: x == G([1/11, 1/11, 0, 10/11]) True - Finally we attempt to convert an element that shouldn't work, - since is is not in `G`:: + Finally we attempt to convert some elements that shouldn't + work, since they are not in `G`:: sage: G(J.torsion_subgroup(3).0) Traceback (most recent call last): ... - TypeError: cannot convert (1/3, 0, 0, 0) into Finite subgroup with invariants [11, 11, 11, 11] over QQ of Abelian variety J0(23) of dimension 2 + TypeError: element [1/3, 0, 0, 0] is not in free module + + sage: G(J0(27).cuspidal_subgroup()(0)) + Traceback (most recent call last): + ... + ValueError: ambient abelian varieties are different + """ if isinstance(x, TorsionPoint): - if x.parent() == self: - return self.element_class(self, x.element(), check=False) - elif x.parent().abelian_variety() == self.abelian_variety(): - return self(x.element(), check=check) - else: - z = self.abelian_variety().vector_space()(x, check=check) - if z in self.lattice(): - return self.element_class(self, z, check=False) - raise TypeError("cannot convert {!r} into {}".format(x, self)) - + if x.parent().abelian_variety() != self.abelian_variety(): + raise ValueError('ambient abelian varieties are different') + x = x.element() + x = self.lattice()(x, check=check) + return self.element_class(self, x, check=False) def __contains__(self, x): """ @@ -697,7 +698,7 @@ def __contains__(self, x): """ try: self(x) - except TypeError: + except (TypeError, ValueError): return False return True From 57e13e6f294218589d95caf5122a1841ecbe71a0 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 28 Apr 2015 22:24:01 -0400 Subject: [PATCH 594/665] let matplotlib decide on the bounding box --- src/sage/graphs/graph_plot.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 922f46b1bf4..03afe2cdb2b 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -912,7 +912,6 @@ def plot(self, **kwds): for item in comp: G += item - G.set_axes_range(*(self._graph._layout_bounding_box(self._pos))) if self._options['graph_border']: xmin = G.xmin() xmax = G.xmax() @@ -925,7 +924,6 @@ def plot(self, **kwds): G += border G.set_aspect_ratio(1) G.axes(False) - G._extra_kwds['axes_pad']=.05 return G def layout_tree(self,root,orientation): From 1172bececa0413e2394b047869d0912ddd7165a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Labb=C3=A9?= Date: Wed, 29 Apr 2015 11:26:42 +0300 Subject: [PATCH 595/665] Did some simplifications --- src/sage/geometry/polyhedron/plot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 048196d5bd5..0c5ef7ea9ef 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -238,7 +238,7 @@ def cyclic_sort_vertices_2d(Vlist): A line in the direction (1, 0), A ray in the direction (0, 1)] """ - if len(Vlist) == 0: + if not Vlist: return Vlist Vlist = list(Vlist) result = [] @@ -246,7 +246,7 @@ def cyclic_sort_vertices_2d(Vlist): # Any object in Vlist has 0,1, or 2 adjacencies. Break into connected chains: chain = [ Vlist.pop() ] - while len(Vlist) > 0: + while Vlist: first_index = chain[0].index() last_index = chain[-1].index() for v in Vlist: From e08010c103701ba560d0a31432fd67ed7b7de958 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 29 Apr 2015 14:10:54 +0200 Subject: [PATCH 596/665] Trac 18332: is_integer and is_rational for number field elements --- .../number_field/number_field_element.pyx | 40 +++++++++++++++++++ .../number_field_element_quadratic.pyx | 40 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index e54bb0cd8f7..fb15273f194 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2646,6 +2646,46 @@ cdef class NumberFieldElement(FieldElement): cdef bint is_rational_c(self): return ZZX_deg(self.__numerator) == 0 + def is_rational(self): + r""" + Test whether this number field element is a rational + + EXAMPLES:: + + sage: K. = NumberField(x^3 - 3) + sage: cbrt3.is_rational() + False + sage: (cbrt3**2 - cbrt3 + 1/2).is_rational() + False + sage: K(-12).is_rational() + True + sage: K(0).is_rational() + True + sage: K(1/2).is_rational() + True + """ + return ZZX_deg(self.__numerator) <= 0 + + def is_integer(self): + r""" + Test whether this number field element is an integer + + EXAMPLES:: + + sage: K. = NumberField(x^3 - 3) + sage: cbrt3.is_integer() + False + sage: (cbrt3**2 - cbrt3 + 2).is_integer() + False + sage: K(-12).is_integer() + True + sage: K(0).is_integer() + True + sage: K(1/2).is_integer() + False + """ + return ZZX_deg(self.__numerator) <= 0 and ZZ_IsOne(self.__denominator) == 1 + def trace(self, K=None): """ Return the absolute or relative trace of this number field diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 32e1acc684f..493dace652f 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -1392,6 +1392,46 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpq_canonicalize(res.value) return res + def is_rational(self): + r""" + Check whether this number field element is a rational number. + + EXAMPLES:: + + sage: K. = QuadraticField(3) + sage: sqrt3.is_rational() + False + sage: (sqrt3-1/2).is_rational() + False + sage: K(0).is_rational() + True + sage: K(-12).is_rational() + True + sage: K(1/3).is_rational() + True + """ + return mpz_cmp_ui(self.b, 0) == 0 + + def is_integer(self): + r""" + Check whether this number field element is an integer. + + EXAMPLES:: + + sage: K. = QuadraticField(3) + sage: sqrt3.is_integer() + False + sage: (sqrt3-1/2).is_integer() + False + sage: K(0).is_integer() + True + sage: K(-12).is_integer() + True + sage: K(1/3).is_integer() + False + """ + return mpz_cmp_ui(self.b, 0) == mpz_cmp_ui(self.denom, 1) == 0 + def real(self): r""" Returns the real part of self, which is either self (if self lives From a9f34ad605c82f44bb72143a8d45ee1aaf70809f Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 29 Apr 2015 14:57:00 +0200 Subject: [PATCH 597/665] trac #18335: Compute the degree of a vertex without using networkX --- src/sage/graphs/graph.py | 59 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 881dbfbd1fd..79c09859198 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4606,45 +4606,50 @@ def convexity_properties(self): # Centrality def centrality_degree(self, v=None): r""" - Returns the degree centrality (fraction of vertices connected to) - as a dictionary of values keyed by vertex. The degree centrality is - normalized to be in range (0,1). + Returns the degree centrality of a vertex. - Measures of the centrality of a vertex within a graph determine the - relative importance of that vertex to its graph. Degree centrality - measures the number of links incident upon a vertex. + The degree centrality of a vertex `v` is its degree, divided by + `n-1`. For more information, see the :wikipedia:`Centrality`. INPUT: - - - ``v`` - a vertex label (to find degree centrality of - only one vertex) - + - ``v`` - a vertex. Set to ``None`` (default) to get a dictionary + associating each vertex with its centrality degree. EXAMPLES:: sage: (graphs.ChvatalGraph()).centrality_degree() - {0: 0.36363636363636365, 1: 0.36363636363636365, 2: 0.36363636363636365, 3: 0.36363636363636365, 4: 0.36363636363636365, 5: 0.36363636363636365, 6: 0.36363636363636365, 7: 0.36363636363636365, 8: 0.36363636363636365, 9: 0.36363636363636365, 10: 0.36363636363636365, 11: 0.36363636363636365} - sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: D.show(figsize=[2,2]) - sage: D = D.to_undirected() - sage: D.show(figsize=[2,2]) + {0: 4/11, 1: 4/11, 2: 4/11, 3: 4/11, 4: 4/11, 5: 4/11, + 6: 4/11, 7: 4/11, 8: 4/11, 9: 4/11, 10: 4/11, 11: 4/11} + sage: D = graphs.DiamondGraph() sage: D.centrality_degree() - {0: 1.0, 1: 1.0, 2: 0.6666666666666666, 3: 0.6666666666666666} + {0: 2/3, 1: 1, 2: 1, 3: 2/3} sage: D.centrality_degree(v=1) - 1.0 + 1 + + TESTS:: + + sage: Graph(1).centrality_degree() + Traceback (most recent call last): + ... + ValueError: The centrality degree is not defined on graphs with only one vertex """ - import networkx + from sage.rings.integer import Integer + n_minus_one = Integer(self.order()-1) + if n_minus_one == 0: + raise ValueError("The centrality degree is not defined " + "on graphs with only one vertex") if v is None: - return networkx.degree_centrality(self.networkx_graph(copy=False)) + return {v:self.degree(v)/n_minus_one for v in self} else: - return networkx.degree_centrality(self.networkx_graph(copy=False))[v] + return self.degree(v)/n_minus_one def centrality_closeness(self, v=None): r""" - Returns the closeness centrality (1/average distance to all - vertices) as a dictionary of values keyed by vertex. The degree - centrality is normalized to be in range (0,1). + Returns the closeness centrality of a vertex. + + The closeness centrality of a vertex `v` is equal to the inverse of [the + average distance between `v` and other vertices]. Measures of the centrality of a vertex within a graph determine the relative importance of that vertex to its graph. 'Closeness @@ -4654,12 +4659,12 @@ def centrality_closeness(self, v=None): central actor while a smaller value indicates a more central actor,' [Borgatti95]_. - INPUT: - + For more information, see the :wikipedia:`Centraliy`. - - ``v`` - a vertex label (to find degree centrality of - only one vertex) + INPUT: + - ``v`` - a vertex. Set to ``None`` (default) to get a dictionary + associating each vertex with its centrality closeness. REFERENCE: From d96885c0b700b6ae5f703dcf62dae6cf62323759 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 29 Apr 2015 14:57:45 +0200 Subject: [PATCH 598/665] Trac 18334: sign and truncations for real intervals --- src/sage/rings/real_mpfi.pyx | 307 ++++++++++++++++++++++++----------- 1 file changed, 209 insertions(+), 98 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 863d3275a07..3a559102c58 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -2510,22 +2510,6 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): mpfi_alea(x.value, self.value) return x -# def integer_part(self): -# """ -# If in decimal this number is written n.defg, returns n. - -# OUTPUT: -# -- a Sage Integer - -# EXAMPLE: -# sage: a = 119.41212 -# sage: a.integer_part() -# 119 -# """ -# s = self.str(base=32, no_sci=True) -# i = s.find(".") -# return Integer(s[:i], base=32) - ######################## # Basic Arithmetic ######################## @@ -2831,9 +2815,6 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): return 2 return sage.rings.infinity.infinity -# def sign(self): -# return mpfr_sgn(self.value) - def precision(self): """ Returns the precision of ``self``. @@ -2853,50 +2834,20 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): # Rounding etc ################### - # Not implemented on intervals (for good reason!) -# def round(self): -# """ -# Rounds self to the nearest real number. There are 4 -# rounding modes. They are - -# EXAMPLES: -# RNDN -- round to nearest: - -# sage: R = RealIntervalField(20,False,'RNDN') -# sage: R(22.454) -# 22.454 -# sage: R(22.491) -# 22.490 - -# RNDZ -- round towards zero: -# sage: R = RealIntervalField(20,False,'RNDZ') -# sage: R(22.454) -# 22.453 -# sage: R(22.491) -# 22.490 - -# RNDU -- round towards plus infinity: -# sage: R = RealIntervalField(20,False,'RNDU') -# sage: R(22.454) -# 22.454 -# sage: R(22.491) -# 22.491 - -# RNDU -- round towards minus infinity: -# sage: R = RealIntervalField(20,False,'RNDD') -# sage: R(22.454) -# 22.453 -# sage: R(22.491) -# 22.490 -# """ -# cdef RealIntervalFieldElement x -# x = self._new() -# mpfr_round(x.value, self.value) -# return x - def floor(self): """ - Return the floor of ``self``. + Return the floor of this interval as an interval + + The floor of a real number `x` is the largest integer smaller than or + equal to `x`. + + .. SEEALSO:: + + - :meth:`unique_floor` -- method which returns the floor as an integer + if it is unique or raises a ``ValueError`` otherwise. + - :meth:`ceil` -- truncation towards plus infinity + - :meth:`round` -- rounding + - :meth:`trunc` -- truncation towards zero EXAMPLES:: @@ -2923,11 +2874,18 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): def ceil(self): """ - Return the ceiling of ``self``. + Return the celing of this interval as an interval - OUTPUT: + The ceiling of a real number `x` is the smallest integer larger than or + equal to `x`. + + .. SEEALSO:: - integer + - :meth:`unique_ceil` -- return the ceil as an integer if it is + unique and raises a ``ValueError`` otherwise + - :meth:`floor` -- truncation towards minus infinity + - :meth:`trunc` -- truncation towards zero + - :meth:`round` -- rounding EXAMPLES:: @@ -2951,41 +2909,109 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): ceiling = ceil -# def trunc(self): -# """ -# Truncates this number + def round(self): + r""" + Return the nearest integer of this interval as an interval -# EXAMPLES: -# sage: (2.99).trunc() -# 2.00000000000000 -# sage: (-0.00).trunc() -# -0.000000000000000 -# sage: (0.00).trunc() -# 0.000000000000000 -# """ -# cdef RealIntervalFieldElement x -# x = self._new() -# mpfr_trunc(x.value, self.value) -# return x + .. SEEALSO: -# def frac(self): -# """ -# frac returns a real number > -1 and < 1. it satisfies the -# relation: -# x = x.trunc() + x.frac() + - :meth:`unique_round` -- return the round as an integer if it is + unique and raises a ``ValueError`` otherwise + - :meth:`floor` -- truncation towards `-\infty` + - :meth:`ceil` -- truncation towards `+\infty` + - :meth:`trunc` -- truncation towards `0` -# EXAMPLES: -# sage: (2.99).frac() -# 0.990000000000000 -# sage: (2.50).frac() -# 0.500000000000000 -# sage: (-2.79).frac() -# -0.790000000000000 -# """ -# cdef RealIntervalFieldElement x -# x = self._new() -# mpfr_frac(x.value, self.value, (self._parent).rnd) -# return x + EXAMPLES:: + + sage: RIF(7.2, 7.3).round() + 7 + sage: RIF(-3.2, -3.1).round() + -3 + + Be careful that the answer is not an integer but an interval:: + + sage: RIF(2.2, 2.3).round().parent() + Real Interval Field with 53 bits of precision + + And in some cases, the lower and upper bounds of this interval do not + agree:: + + sage: r = RIF(2.5, 3.5).round() + sage: r + 4.? + sage: r.lower() + 3.00000000000000 + sage: r.upper() + 4.00000000000000 + """ + return self.parent()(self.lower().round(), self.upper().round()) + + def trunc(self): + r""" + Return the truncation of this interval as an interval + + The truncation of `x` is the floor of `x` if `x` is non-negative or the + ceil of `x` if `x` is negative. + + .. SEEALSO:: + + - :meth:`unique_trunc` -- return the trunc as an integer if it is + unique and raises a ``ValueError`` otherwise + - :meth:`floor` -- truncation towards `-\infty` + - :meth:`ceil` -- truncation towards `+\infty` + - :meth:`round` -- rounding + + EXAMPLES:: + + sage: RIF(2.3, 2.7).trunc() + 2 + sage: parent(_) + Real Interval Field with 53 bits of precision + + sage: RIF(-7.5, -7.3).trunc() + -7 + + In the above example, the obtained interval contains only one element. + But on the following it is not the case anymore:: + + sage: r = RIF(2.99, 3.01).trunc() + sage: r.upper() + 3.00000000000000 + sage: r.lower() + 2.00000000000000 + """ + return self.parent()(self.lower().trunc(), self.upper().trunc()) + + def frac(self): + r""" + Return the fractional part of this interval as an interval. + + The fractional part `y` of a real number `x` is the unique element in the + interval `(-1,1)` that has the same sign as `x` and such that `x-y` is + an integer. The integer `x-y` can be obtained through the method + :meth:`trunc`. + + .. SEEALSO:: + + :meth:`trunc` -- return the integer part complement to this + fractional part + + EXAMPLES:: + + sage: RIF(2.37123, 2.372).frac() + 0.372? + sage: RIF(-23.12, -23.13).frac() + -0.13? + + sage: r = RIF(-22.47, -22.468) + sage: r in (r.frac() + r.trunc()) + True + + sage: r = RIF(18.222, 18.223) + sage: r in (r.frac() + r.trunc()) + True + """ + return self.parent()(self.lower().frac(), self.upper().frac()) ########################################### # Conversions @@ -3019,6 +3045,44 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): # def _pari_(self): # return sage.libs.pari.all.pari.new_with_bits_prec(str(self), (self._parent).__prec) + def unique_sign(self): + r""" + Return the sign of this element if it is well defined. + + This method returns `+1` if all elements in this interval are positive, + `-1` if all of them are negative and `0` if it contains only zero. + Otherwise it raises a ``ValueError``. + + EXAMPLES:: + + sage: RIF(1.2,5.7).unique_sign() + 1 + sage: RIF(-3,-2).unique_sign() + -1 + sage: RIF(0).unique_sign() + 0 + sage: RIF(0,1).unique_sign() + Traceback (most recent call last): + ... + ValueError: interval does not have a unique sign + sage: RIF(-1,0).unique_sign() + Traceback (most recent call last): + ... + ValueError: interval does not have a unique sign + sage: RIF(-0.1, 0.1).unique_sign() + Traceback (most recent call last): + ... + ValueError: interval does not have a unique sign + """ + if mpfi_is_zero(self.value): + return 0 + elif mpfi_is_strictly_pos(self.value): + return 1 + elif mpfi_is_strictly_neg(self.value): + return -1 + else: + raise ValueError("interval does not have a unique sign") + def unique_floor(self): """ Returns the unique floor of this interval, if it is well defined, @@ -3028,6 +3092,11 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): - an integer. + .. SEEALSO:: + + :meth:`floor` -- return the floor as an interval (and never raise + error) + EXAMPLES:: sage: RIF(pi).unique_floor() @@ -3054,6 +3123,11 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): - an integer. + .. SEEALSO:: + + :meth:`ceil` -- return the ceil as an interval (and never raise + error) + EXAMPLES:: sage: RIF(pi).unique_ceil() @@ -3080,6 +3154,11 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): - an integer. + .. SEEALSO:: + + :meth:`round` -- return the round as an interval (and never raise + error) + EXAMPLES:: sage: RIF(pi).unique_round() @@ -3130,6 +3209,38 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): else: raise ValueError("interval does not have a unique round (nearest integer)") + def unique_trunc(self): + r""" + Return the nearest integer toward zero if it is unique, otherwise raise + a ``ValueError``. + + .. SEEALSO: + + :meth:`trunc` -- return the truncation as an interval (and never + raise error) + + EXAMPLES:: + + sage: RIF(1.3,1.4).unique_trunc() + 1 + sage: RIF(-3.3, -3.2).unique_trunc() + -3 + sage: RIF(2.9,3.2).unique_trunc() + Traceback (most recent call last): + ... + ValueError: interval does not have a unique trunc (nearest integer toward zero) + sage: RIF(-3.1,-2.9).unique_trunc() + Traceback (most recent call last): + ... + ValueError: interval does not have a unique trunc (nearest integer toward zero) + """ + a = self.lower().trunc() + b = self.upper().trunc() + if a == b: + return a + else: + raise ValueError("interval does not have a unique trunc (nearest integer toward zero)") + def unique_integer(self): """ Return the unique integer in this interval, if there is exactly one, @@ -4653,7 +4764,7 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): return (~self).arctanh() def algdep(self, n): - """ + r""" Returns a polynomial of degree at most `n` which is approximately satisfied by ``self``. @@ -4711,7 +4822,7 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): known_bits = -self.relative_diameter().log2() return sage.rings.arith.algdep(self.center(), n, known_bits=known_bits) - + def factorial(self): """ Return the factorial evaluated on ``self``. From ceb8afd50e10cb316ba2db86310ce4b7390ba434 Mon Sep 17 00:00:00 2001 From: Aladin Virmaux Date: Wed, 29 Apr 2015 15:38:58 +0200 Subject: [PATCH 599/665] 18336: algebra_generators in algebras_with_basis --- src/sage/categories/algebras_with_basis.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 8a4668edf1e..a6e93032ab3 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -193,6 +193,28 @@ def _product_from_combinatorial_algebra_multiply(self,left,right): # tester.assert_(self.product is not None) # could check that self.product is in Hom( self x self, self) + def algebra_generators(self): + r""" + Return algebra generators for this algebra, namely its basis. + + OUTPUT: + + - A family that generate self + + EXAMPLES:: + + sage: D4 = DescentAlgebra(QQ, 4).B() + sage: D4.algebra_generators() + Lazy family (Term map from Compositions of 4 to Descent algebra + of 4 over Rational Field in the subset basis(i))_{i in + Compositions of 4} + sage: R. = ZZ[] + sage: P = PartitionAlgebra(1, x, R) + sage: P.algebra_generators() + Finite family {{{-1, 1}}: P[{{-1, 1}}], {{-1}, {1}}: P[{{-1}, {1}}]} + """ + return self.basis() + class ElementMethods: def __invert__(self): From 073e7c5518d38e74a2d47a2e7cbaabfaf0a23ce5 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Wed, 29 Apr 2015 18:36:31 +0200 Subject: [PATCH 600/665] trac #18335: Review --- src/sage/graphs/generic_graph.py | 5 +++++ src/sage/graphs/graph.py | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c5c58435c9f..f38cee1cb25 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12791,6 +12791,11 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In the latter case, Sage's algorithm will be used whenever possible. + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.centrality_degree` + - :meth:`~sage.graphs.graph.Graph.centrality_closeness` + EXAMPLES:: sage: g = graphs.ChvatalGraph() diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 79c09859198..f1529c18243 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4609,13 +4609,18 @@ def centrality_degree(self, v=None): Returns the degree centrality of a vertex. The degree centrality of a vertex `v` is its degree, divided by - `n-1`. For more information, see the :wikipedia:`Centrality`. + `|V(G)|-1`. For more information, see the :wikipedia:`Centrality`. INPUT: - ``v`` - a vertex. Set to ``None`` (default) to get a dictionary associating each vertex with its centrality degree. + .. SEEALSO:: + + - :meth:`centrality_closeness` + - :meth:`~sage.graphs.generic_graph.GenericGraph.centrality_betweenness` + EXAMPLES:: sage: (graphs.ChvatalGraph()).centrality_degree() @@ -4666,6 +4671,11 @@ def centrality_closeness(self, v=None): - ``v`` - a vertex. Set to ``None`` (default) to get a dictionary associating each vertex with its centrality closeness. + .. SEEALSO:: + + - :meth:`centrality_degree` + - :meth:`~sage.graphs.generic_graph.GenericGraph.centrality_betweenness` + REFERENCE: .. [Borgatti95] Stephen P Borgatti. (1995). Centrality and AIDS. From 5f5d7922635f713194f0f3f9a9215148828a4e4f Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Wed, 29 Apr 2015 19:37:06 +0200 Subject: [PATCH 601/665] Trac 18337: .imag() for real intervals --- src/sage/rings/real_mpfi.pyx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 863d3275a07..daf5d38fa38 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -1446,9 +1446,13 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): def real(self): """ - Return the real part of ``self``. + Return the real part of this real interval. - (Since ``self`` is a real number, this simply returns ``self``.) + (Since this interval is real, this simply returns itself.) + + .. SEEALSO: + + :meth:`imag` EXAMPLES:: @@ -1457,6 +1461,23 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): """ return self + def imag(self): + r""" + Return the imaginary part of this real interval. + + (Since this is interval is real, this simply returns the zero interval.) + + .. SEEALSO:: + + :meth:`real` + + EXAMPLES:: + + sage: RIF(2,3).imag() + 0 + """ + return self._parent.zero() + # MPFR had an elaborate "truncation" scheme to avoid printing # inaccurate-looking results; this has been removed for MPFI, # because I think it's less confusing to get such results than to From f25a702251f231841e44437cef31e70e871973d9 Mon Sep 17 00:00:00 2001 From: Leif Leonhardy Date: Wed, 29 Apr 2015 23:20:46 +0200 Subject: [PATCH 602/665] Add upstream patch to let gf2x's 'make check' actually fail on errors (#18339) Due to a bug in a shell script, previously 'make check' would fail if and only if the *last* test failed. --- build/pkgs/gf2x/SPKG.txt | 3 ++- ...Fix_make_check_not_failing_on_errors.patch | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/gf2x/patches/0006-Fix_make_check_not_failing_on_errors.patch diff --git a/build/pkgs/gf2x/SPKG.txt b/build/pkgs/gf2x/SPKG.txt index d4e9f208d92..f383bef530c 100644 --- a/build/pkgs/gf2x/SPKG.txt +++ b/build/pkgs/gf2x/SPKG.txt @@ -36,4 +36,5 @@ Website: http://gf2x.gforge.inria.fr/ * 0005-Update-autotooled-files.patch: the above patches make changes to code used by autotools for generation of the build system. This patches those files, so that autotools need not be installed. - + * 0006-Fix_make_check_not_failing_on_errors.patch: (upstream patch) + Fix bug in shell script such that 'make check' always fails upon errors. diff --git a/build/pkgs/gf2x/patches/0006-Fix_make_check_not_failing_on_errors.patch b/build/pkgs/gf2x/patches/0006-Fix_make_check_not_failing_on_errors.patch new file mode 100644 index 00000000000..8cdbf1e4be2 --- /dev/null +++ b/build/pkgs/gf2x/patches/0006-Fix_make_check_not_failing_on_errors.patch @@ -0,0 +1,27 @@ +Upstream patch, added by Sage trac ticket #18339. +(gf2x's test suite may "pass" even though it actually failed.) + +See also https://gforge.inria.fr/tracker/index.php?func=detail&aid=18889&group_id=1874&atid=6979 + +commit 13e8d124c7598d3b0e51ee7cb385435cd2ec57f5 +Author: Emmanuel Thomé +Date: Wed Apr 29 09:58:12 2015 +0200 + + fix #18889 + +diff --git a/tests/do-check-mul.sh b/tests/do-check-mul.sh +index 275414d..96c140f 100755 +--- a/tests/do-check-mul.sh ++++ b/tests/do-check-mul.sh +@@ -36,6 +36,11 @@ cat "$srcdir/check-mul.res" | while read n1 n2 v s ; do + exit 1 + fi + done ++ ++if [ $? -ne 0 ]; then ++ exit 1 ++fi ++ + echo + + ./check-addmul From 84ebf31d352e519253a07247c9fe2d3c3fa85b6a Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 30 Apr 2015 11:05:12 +0200 Subject: [PATCH 603/665] Upgrade PARI/GP --- build/pkgs/pari/checksums.ini | 6 +- build/pkgs/pari/package-version.txt | 2 +- build/pkgs/pari/patches/get_fltk.patch | 19 - src/sage/libs/pari/decl.pxi | 510 +++++++++++++++++++------ src/sage/libs/pari/gen.pyx | 11 +- src/sage/libs/pari/pari_instance.pyx | 2 +- 6 files changed, 415 insertions(+), 135 deletions(-) delete mode 100644 build/pkgs/pari/patches/get_fltk.patch diff --git a/build/pkgs/pari/checksums.ini b/build/pkgs/pari/checksums.ini index 30e411f46d1..e89ff9db140 100644 --- a/build/pkgs/pari/checksums.ini +++ b/build/pkgs/pari/checksums.ini @@ -1,4 +1,4 @@ tarball=pari-VERSION.tar.gz -sha1=7617f60af26582d4a77e5af413b26fde32bd4f1a -md5=2ae5684a10d557016fc1b6ad10b8bf80 -cksum=4177496658 +sha1=158c434517a8c8d36d1c4f1d933d5d7b3e1fada9 +md5=ecef60dc314b75aa1f5d311f22642bb6 +cksum=3629598448 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index e97a033ae59..8b0d89d3659 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.8-1369-g0e48e9b.p0 +2.8-1545-gd04cdd3.p0 diff --git a/build/pkgs/pari/patches/get_fltk.patch b/build/pkgs/pari/patches/get_fltk.patch deleted file mode 100644 index ea32c5fcd6e..00000000000 --- a/build/pkgs/pari/patches/get_fltk.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -ru src/config/get_fltk b/config/get_fltk ---- src/config/get_fltk 2014-02-01 16:36:02.492702307 +0100 -+++ b/config/get_fltk 2014-02-01 16:43:22.183289684 +0100 -@@ -16,8 +16,15 @@ - fi;; - esac - if test -n "$FLTKDIR"; then -+ if test -d "$FLTKDIR/include/FL"; then - echo "Using FLTK library, FLTKDIR = $FLTKDIR" - FLTK_LIBS="`fltk-config --ldflags` -lstdc++" -+ else -+ echo "### Found the FLTK library, but not the necessary headers." -+ echo "### Building without FLTK support." -+ FLTKDIR="" -+ FLTK_LIBS="" -+ fi - else - echo "### FLTK not found. Building without FLTK support" - FLTK_LIBS= diff --git a/src/sage/libs/pari/decl.pxi b/src/sage/libs/pari/decl.pxi index ae28af6a6d5..ac84909ea6b 100644 --- a/src/sage/libs/pari/decl.pxi +++ b/src/sage/libs/pari/decl.pxi @@ -38,44 +38,25 @@ cdef extern from "sage/libs/pari/parisage.h": # Various structures that we don't use in Sage but which need to be # declared, otherwise Cython complains. - struct bb_group: - pass - struct bb_field: - pass - struct bb_ring: - pass - struct bb_algebra: - pass - struct qfr_data: - pass - struct nfmaxord_t: - pass - struct forcomposite_t: - pass - struct forpart_t: - pass - struct forprime_t: - pass - struct forvec_t: - pass - struct entree: - pass - struct gp_context: - pass - struct pariFILE: - pass - struct pari_mt: - pass - struct pari_thread: - pass - struct pari_timer: - pass - struct GENbin: - pass - struct hashentry: - pass - struct hashtable: - pass + struct bb_group + struct bb_field + struct bb_ring + struct bb_algebra + struct qfr_data + struct nfmaxord_t + struct forcomposite_t + struct forpart_t + struct forprime_t + struct forvec_t + struct entree + struct gp_context + struct pariFILE + struct pari_mt + struct pari_thread + struct pari_timer + struct GENbin + struct hashentry + struct hashtable # PARI types: these are actually an enum type, but that doesn't # matter for Cython. @@ -293,6 +274,32 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgE_to_F2xqE(GEN x, GEN T) GEN random_F2xqE(GEN a2, GEN a6, GEN T) + # Fle.c + + ulong Fl_elldisc(ulong a4, ulong a6, ulong p) + ulong Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi) + ulong Fl_ellj(ulong a4, ulong a6, ulong p) + void Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6) + void Fl_elltwist(ulong a4, ulong a6, ulong D, ulong p, ulong *pt_a4, ulong *pt_a6) + GEN Fle_add(GEN P, GEN Q, ulong a4, ulong p) + GEN Fle_dbl(GEN P, ulong a4, ulong p) + GEN Fle_changepoint(GEN x, GEN ch, ulong p) + GEN Fle_changepointinv(GEN x, GEN ch, ulong p) + GEN Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p) + GEN Fle_mul(GEN P, GEN n, ulong a4, ulong p) + GEN Fle_mulu(GEN P, ulong n, ulong a4, ulong p) + GEN Fle_order(GEN z, GEN o, ulong a4, ulong p) + GEN Fle_sub(GEN P, GEN Q, ulong a4, ulong p) + GEN Fle_to_Flj(GEN P) + GEN Flj_add_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi) + GEN Flj_dbl_pre(GEN P, ulong a4, ulong p, ulong pi) + GEN Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi) + GEN Flj_neg(GEN Q, ulong p) + GEN Flj_to_Fle_pre(GEN P, ulong p, ulong pi) + GEN random_Fle(ulong a4, ulong a6, ulong p) + GEN random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi) + GEN random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi) + # Flx.c bb_group * get_Flxq_star(void **E, GEN T, ulong p) @@ -310,6 +317,9 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flm_to_ZM(GEN z) GEN Flv_FlvV_polint(GEN xa, GEN ya, ulong p, long vs) GEN Flv_inv(GEN x, ulong p) + void Flv_inv_inplace(GEN x, ulong p) + void Flv_inv_pre_inplace(GEN x, ulong p, ulong pi) + GEN Flv_inv_pre(GEN x, ulong p, ulong pi) GEN Flv_polint(GEN xa, GEN ya, ulong p, long vs) GEN Flv_roots_to_pol(GEN a, ulong p, long vs) GEN Flv_to_Flx(GEN x, long vs) @@ -318,7 +328,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flx_Fl_add(GEN y, ulong x, ulong p) GEN Flx_Fl_mul(GEN y, ulong x, ulong p) GEN Flx_Fl_mul_to_monic(GEN y, ulong x, ulong p) - GEN Flx_Flv_eval(GEN P, GEN v, ulong p) + GEN Flx_Fl2_eval_pre(GEN x, GEN y, ulong D, ulong p, ulong pi) + GEN Flx_Flv_multieval(GEN P, GEN v, ulong p) GEN Flx_Flxq_eval(GEN f, GEN x, GEN T, ulong p) GEN Flx_FlxqV_eval(GEN f, GEN x, GEN T, ulong p) GEN Flx_Frobenius(GEN T, ulong p) @@ -330,6 +341,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flx_divrem(GEN x, GEN y, ulong p, GEN *pr) int Flx_equal(GEN V, GEN W) ulong Flx_eval(GEN x, ulong y, ulong p) + ulong Flx_eval_powers_pre(GEN x, GEN y, ulong p, ulong pi) + ulong Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi) GEN Flx_extgcd(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv) ulong Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV) GEN Flx_gcd(GEN a, GEN b, ulong p) @@ -368,10 +381,11 @@ cdef extern from "sage/libs/pari/parisage.h": GEN FlxM_Flx_add_shallow(GEN x, GEN y, ulong p) GEN FlxM_to_ZXM(GEN z) GEN FlxT_red(GEN z, ulong p) - GEN FlxV_to_ZXV(GEN x) GEN FlxV_Flc_mul(GEN V, GEN W, ulong p) + GEN FlxV_prod(GEN V, ulong p) GEN FlxV_red(GEN z, ulong p) GEN FlxV_to_Flm(GEN v, long n) + GEN FlxV_to_ZXV(GEN x) GEN FlxX_Fl_mul(GEN x, ulong y, ulong p) GEN FlxX_Flx_add(GEN y, GEN x, ulong p) GEN FlxX_Flx_mul(GEN x, GEN y, ulong p) @@ -390,7 +404,9 @@ cdef extern from "sage/libs/pari/parisage.h": GEN FlxY_Flxq_evalx(GEN P, GEN x, GEN T, ulong p) GEN FlxY_FlxqV_evalx(GEN P, GEN x, GEN T, ulong p) GEN FlxY_Flx_div(GEN x, GEN y, ulong p) + ulong FlxY_eval_powers_pre(GEN pol, GEN ypowers, GEN xpowers, ulong p, ulong pi) GEN FlxY_evalx(GEN Q, ulong x, ulong p) + GEN FlxY_evalx_powers_pre(GEN pol, GEN ypowers, ulong p, ulong pi) GEN FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p) GEN Flxq_autpow(GEN x, ulong n, GEN T, ulong p) GEN Flxq_autsum(GEN x, ulong n, GEN T, ulong p) @@ -461,6 +477,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN pol1_FlxX(long v, long sv) GEN polx_FlxX(long v, long sv) GEN random_Flx(long d1, long v, ulong p) + GEN zx_to_Flx(GEN x, ulong p) + GEN zxX_to_FlxX(GEN B, ulong p) GEN zxX_to_Kronecker(GEN P, GEN Q) # FlxqE.c @@ -469,6 +487,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flxq_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p) GEN Flxq_ellgroup(GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pt_m) GEN Flxq_ellj(GEN a4, GEN a6, GEN T, ulong p) + void Flxq_ellj_to_a4a6(GEN j, GEN T, ulong p, GEN *pt_a4, GEN *pt_a6) GEN FlxqE_add(GEN P, GEN Q, GEN a4, GEN T, ulong p) GEN FlxqE_changepoint(GEN x, GEN ch, GEN T, ulong p) GEN FlxqE_changepointinv(GEN x, GEN ch, GEN T, ulong p) @@ -487,17 +506,13 @@ cdef extern from "sage/libs/pari/parisage.h": # FpE.c long Fl_elltrace(ulong a4, ulong a6, ulong p) - GEN Fle_add(GEN P, GEN Q, ulong a4, ulong p) - GEN Fle_dbl(GEN P, ulong a4, ulong p) - GEN Fle_mul(GEN P, GEN n, ulong a4, ulong p) - GEN Fle_mulu(GEN P, ulong n, ulong a4, ulong p) - GEN Fle_order(GEN z, GEN o, ulong a4, ulong p) - GEN Fle_sub(GEN P, GEN Q, ulong a4, ulong p) + long Fl_elltrace_CM(long CM, ulong a4, ulong a6, ulong p) GEN Fp_ellcard(GEN a4, GEN a6, GEN p) GEN Fp_elldivpol(GEN a4, GEN a6, long n, GEN p) GEN Fp_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p) GEN Fp_ellgroup(GEN a4, GEN a6, GEN N, GEN p, GEN *pt_m) GEN Fp_ellj(GEN a4, GEN a6, GEN p) + int Fp_elljissupersingular(GEN j, GEN p) GEN Fp_ffellcard(GEN a4, GEN a6, GEN q, long n, GEN p) GEN FpE_add(GEN P, GEN Q, GEN a4, GEN p) GEN FpE_changepoint(GEN x, GEN ch, GEN p) @@ -516,6 +531,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN FpXQ_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p) GEN FpXQ_ellgroup(GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pt_m) GEN FpXQ_ellj(GEN a4, GEN a6, GEN T, GEN p) + int FpXQ_elljissupersingular(GEN j, GEN T, GEN p) GEN FpXQE_add(GEN P, GEN Q, GEN a4, GEN T, GEN p) GEN FpXQE_changepoint(GEN x, GEN ch, GEN T, GEN p) GEN FpXQE_changepointinv(GEN x, GEN ch, GEN T, GEN p) @@ -533,7 +549,6 @@ cdef extern from "sage/libs/pari/parisage.h": bb_group * get_FpE_group(void **E, GEN a4, GEN a6, GEN p) bb_group * get_FpXQE_group(void **E, GEN a4, GEN a6, GEN T, GEN p) GEN elltrace_extension(GEN t, long n, GEN p) - GEN random_Fle(ulong a4, ulong a6, ulong p) GEN random_FpE(GEN a4, GEN a6, GEN p) GEN random_FpXQE(GEN a4, GEN a6, GEN T, GEN p) @@ -640,6 +655,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flx_nbfact_by_degree(GEN z, long *nb, ulong p) long Flx_nbroots(GEN f, ulong p) ulong Flx_oneroot(GEN f, ulong p) + ulong Flx_oneroot_split(GEN f, ulong p) GEN Flx_roots(GEN f, ulong p) GEN FlxqX_Frobenius(GEN S, GEN T, ulong p) GEN FlxqXQ_halfFrobenius(GEN a, GEN S, GEN T, ulong p) @@ -677,6 +693,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN FpXQX_FpXQ_mul(GEN P, GEN U, GEN T, GEN p) GEN FpXQX_FpXQXQV_eval(GEN P, GEN V, GEN S, GEN T, GEN p) GEN FpXQX_FpXQXQ_eval(GEN P, GEN x, GEN S, GEN T, GEN p) + GEN FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *pr) GEN FpXQX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *pr) GEN FpXQX_divrem_Barrett(GEN x, GEN B, GEN S, GEN T, GEN p, GEN *pr) GEN FpXQX_digits(GEN x, GEN B, GEN T, GEN p) @@ -717,6 +734,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Kronecker_to_FpXQX(GEN z, GEN pol, GEN p) GEN Kronecker_to_ZXX(GEN z, long N, long v) GEN ZXX_mul_Kronecker(GEN x, GEN y, long n) + GEN ZXX_sqr_Kronecker(GEN x, long n) # FpV.c @@ -733,6 +751,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flm_Fl_mul(GEN y, ulong x, ulong p) void Flm_Fl_mul_inplace(GEN y, ulong x, ulong p) GEN Flm_Flc_mul(GEN x, GEN y, ulong p) + GEN Flm_Flc_mul_pre(GEN x, GEN y, ulong p, ulong pi) + GEN Flm_add(GEN x, GEN y, ulong p) GEN Flm_center(GEN z, ulong p, ulong ps2) GEN Flm_mul(GEN x, GEN y, ulong p) GEN Flm_neg(GEN y, ulong p) @@ -742,6 +762,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Flv_add(GEN x, GEN y, ulong p) void Flv_add_inplace(GEN x, GEN y, ulong p) ulong Flv_dotproduct(GEN x, GEN y, ulong p) + ulong Flv_dotproduct_pre(GEN x, GEN y, ulong p, ulong pi) GEN Flv_center(GEN z, ulong p, ulong ps2) GEN Flv_sub(GEN x, GEN y, ulong p) void Flv_sub_inplace(GEN x, GEN y, ulong p) @@ -750,11 +771,15 @@ cdef extern from "sage/libs/pari/parisage.h": GEN FpC_FpV_mul(GEN x, GEN y, GEN p) GEN FpC_Fp_mul(GEN x, GEN y, GEN p) GEN FpC_center(GEN z, GEN p, GEN pov2) + void FpC_center_inplace(GEN z, GEN p, GEN pov2) GEN FpC_red(GEN z, GEN p) GEN FpC_to_mod(GEN z, GEN p) + GEN FpM_add(GEN x, GEN y, GEN p) + GEN FpM_Fp_mul(GEN X, GEN c, GEN p) GEN FpM_FpC_mul(GEN x, GEN y, GEN p) GEN FpM_FpC_mul_FpX(GEN x, GEN y, GEN p, long v) GEN FpM_center(GEN z, GEN p, GEN pov2) + void FpM_center_inplace(GEN z, GEN p, GEN pov2) GEN FpM_mul(GEN x, GEN y, GEN p) GEN FpM_powu(GEN x, ulong n, GEN p) GEN FpM_red(GEN z, GEN p) @@ -787,9 +812,11 @@ cdef extern from "sage/libs/pari/parisage.h": GEN zCs_to_ZC(GEN C, long nbrow) GEN zMs_to_ZM(GEN M, long nbrow) GEN zMs_ZC_mul(GEN M, GEN B) + GEN ZMV_to_FlmV(GEN z, ulong m) # Hensel.c + GEN Zp_sqrt(GEN x, GEN p, long e) GEN Zp_sqrtlift(GEN b, GEN a, GEN p, long e) GEN Zp_sqrtnlift(GEN b, GEN n, GEN a, GEN p, long e) GEN ZpX_Frobenius(GEN T, GEN p, long e) @@ -803,6 +830,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ZpXQ_inv(GEN a, GEN T, GEN p, long e) GEN ZpXQ_invlift(GEN b, GEN a, GEN T, GEN p, long e) GEN ZpXQ_log(GEN a, GEN T, GEN p, long N) + GEN ZpXQ_sqrt(GEN a, GEN T, GEN p, long e) GEN ZpXQ_sqrtnlift(GEN b, GEN n, GEN a, GEN T, GEN p, long e) GEN ZpXQM_prodFrobenius(GEN M, GEN T, GEN p, long e) GEN ZpXQX_liftroot(GEN f, GEN a, GEN T, GEN p, long e) @@ -835,6 +863,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgC_RgM_mul(GEN x, GEN y) GEN RgC_RgV_mul(GEN x, GEN y) GEN RgC_add(GEN x, GEN y) + long RgC_is_ei(GEN x) GEN RgC_neg(GEN x) GEN RgC_sub(GEN x, GEN y) GEN RgM_Rg_add(GEN x, GEN y) @@ -857,6 +886,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgM_powers(GEN x, long l) GEN RgM_sqr(GEN x) GEN RgM_sub(GEN x, GEN y) + GEN RgM_sumcol(GEN A) GEN RgM_transmul(GEN x, GEN y) GEN RgM_transmultosym(GEN x, GEN y) GEN RgM_zc_mul(GEN x, GEN y) @@ -871,6 +901,7 @@ cdef extern from "sage/libs/pari/parisage.h": int RgV_is_ZMV(GEN V) long RgV_isin(GEN v, GEN x) GEN RgV_neg(GEN x) + GEN RgV_prod(GEN v) GEN RgV_sub(GEN x, GEN y) GEN RgV_sum(GEN v) GEN RgV_sumpart(GEN v, long n) @@ -912,8 +943,10 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgX_Rg_add_shallow(GEN y, GEN x) GEN RgX_Rg_div(GEN y, GEN x) GEN RgX_Rg_divexact(GEN x, GEN y) + GEN RgX_Rg_eval_bk(GEN Q, GEN x) GEN RgX_Rg_mul(GEN y, GEN x) GEN RgX_Rg_sub(GEN y, GEN x) + GEN RgX_RgV_eval(GEN Q, GEN x) GEN RgX_add(GEN x, GEN y) GEN RgX_blocks(GEN P, long n, long m) GEN RgX_deflate(GEN x0, long d) @@ -968,6 +1001,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgXV_to_RgM(GEN v, long n) GEN RgXV_unscale(GEN v, GEN h) GEN RgXX_to_RgM(GEN v, long n) + long RgXY_degreex(GEN bpol) GEN RgXY_swap(GEN x, long n, long w) GEN RgXY_swapspec(GEN x, long n, long w, long nx) GEN RgXn_eval(GEN Q, GEN x, long n) @@ -1017,6 +1051,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ZC_add(GEN x, GEN y) GEN ZC_copy(GEN x) GEN ZC_hnfremdiv(GEN x, GEN y, GEN *Q) + long ZC_is_ei(GEN x) GEN ZC_lincomb(GEN u, GEN v, GEN X, GEN Y) void ZC_lincomb1_inplace(GEN X, GEN Y, GEN v) GEN ZC_neg(GEN M) @@ -1025,6 +1060,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ZC_sub(GEN x, GEN y) GEN ZC_z_mul(GEN X, long c) GEN ZM_ZC_mul(GEN x, GEN y) + GEN ZM_Z_div(GEN X, GEN c) GEN ZM_Z_divexact(GEN X, GEN c) GEN ZM_Z_mul(GEN X, GEN c) GEN ZM_add(GEN x, GEN y) @@ -1104,6 +1140,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ZX_add(GEN x, GEN y) GEN ZX_copy(GEN x) GEN ZX_deriv(GEN x) + GEN ZX_div_by_X_1(GEN a, GEN *r) int ZX_equal(GEN V, GEN W) GEN ZX_eval1(GEN x) long ZX_max_lg(GEN x) @@ -1130,6 +1167,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ZXV_remi2n(GEN x, long n) GEN ZXX_Z_divexact(GEN y, GEN x) GEN ZXX_Z_mul(GEN y, GEN x) + GEN ZXX_Z_add_shallow(GEN x, GEN y) long ZXX_max_lg(GEN x) GEN ZXX_renormalize(GEN x, long lx) GEN ZXX_to_Kronecker(GEN P, long n) @@ -1138,6 +1176,120 @@ cdef extern from "sage/libs/pari/parisage.h": GEN scalar_ZX_shallow(GEN x, long v) GEN zx_to_ZX(GEN z) + # algebras.c + + GEN alg_centralproj(GEN al, GEN z, int maps) + GEN alg_change_overorder_shallow(GEN al, GEN ord) + GEN alg_complete(GEN rnf, GEN aut, GEN hi, GEN hf, int maxord) + GEN alg_csa_table(GEN nf, GEN mt, long v, int maxord) + GEN alg_cyclic(GEN rnf, GEN aut, GEN b, int maxord) + GEN alg_decomposition(GEN al) + long alg_get_absdim(GEN al) + long algabsdim(GEN al) + GEN alg_get_abssplitting(GEN al) + GEN alg_get_aut(GEN al) + GEN algaut(GEN al) + GEN alg_get_auts(GEN al) + GEN alg_get_b(GEN al) + GEN algb(GEN al) + GEN alg_get_center(GEN al) + GEN alggetcenter(GEN al) + GEN alg_get_char(GEN al) + GEN algchar(GEN al) + long alg_get_degree(GEN al) + long algdegree(GEN al) + long alg_get_dim(GEN al) + long algdim(GEN al) + GEN alg_get_hasse_f(GEN al) + GEN alghassef(GEN al) + GEN alg_get_hasse_i(GEN al) + GEN alghassei(GEN al) + GEN alg_get_invord(GEN al) + GEN alginvbasis(GEN al) + GEN alg_get_multable(GEN al) + GEN alggetmultable(GEN al) + GEN alg_get_ord(GEN al) + GEN algbasis(GEN al) + GEN alg_get_relmultable(GEN al) + GEN algrelmultable(GEN al) + GEN alg_get_splitpol(GEN al) + GEN alg_get_splitting(GEN al) + GEN algsplittingfield(GEN al) + GEN alg_get_splittingbasis(GEN al) + GEN alg_get_splittingbasisinv(GEN al) + GEN alg_get_splittingdata(GEN al) + GEN algsplittingdata(GEN al) + GEN alg_get_tracebasis(GEN al) + GEN alg_hasse(GEN nf, long n, GEN hi, GEN hf, long var, long flag) + GEN alg_hilbert(GEN nf, GEN a, GEN b, long v, long flag) + GEN alg_matrix(GEN nf, long n, long v, GEN L, long flag) + long alg_model(GEN al, GEN x) + GEN alg_ordermodp(GEN al, GEN p) + GEN alg_quotient(GEN al, GEN I, int maps) + GEN algradical(GEN al) + GEN algsimpledec(GEN al, int maps) + GEN algsubalg(GEN al, GEN basis) + long alg_type(GEN al) + GEN algadd(GEN al, GEN x, GEN y) + GEN algalgtobasis(GEN al, GEN x) + GEN algbasischarpoly(GEN al, GEN x, long v) + GEN algbasismul(GEN al, GEN x, GEN y) + GEN algbasismultable(GEN al, GEN x) + GEN algbasismultable_Flm(GEN mt, GEN x, ulong m) + GEN algbasistoalg(GEN al, GEN x) + GEN algcenter(GEN al) + GEN algcharpoly(GEN al, GEN x, long v) + GEN algdisc(GEN al) + GEN algdivl(GEN al, GEN x, GEN y) + GEN algdivr(GEN al, GEN x, GEN y) + GEN alghasse(GEN al, GEN pl) + GEN alginit(GEN A, GEN B, long v, long flag) + long algindex(GEN al, GEN pl) + GEN alginv(GEN al, GEN x) + int algisassociative(GEN mt0, GEN p) + int algiscommutative(GEN al) + int algisdivision(GEN al, GEN pl) + int algisramified(GEN al, GEN pl) + int algissemisimple(GEN al) + int algissimple(GEN al, long ss) + int algissplit(GEN al, GEN pl) + int algisdivl(GEN al, GEN x, GEN y, GEN* ptz) + int algisinv(GEN al, GEN x, GEN* ptix) + GEN algleftordermodp(GEN al, GEN Ip, GEN p) + GEN algmul(GEN al, GEN x, GEN y) + GEN algmultable(GEN al, GEN x) + GEN algneg(GEN al, GEN x) + GEN algnorm(GEN al, GEN x) + GEN algpoleval(GEN al, GEN pol, GEN x) + GEN algpow(GEN al, GEN x, GEN n) + GEN algprimesubalg(GEN al) + GEN algramifiedplaces(GEN al) + GEN algrandom(GEN al, GEN b) + GEN algsplittingmatrix(GEN al, GEN x) + GEN algsqr(GEN al, GEN x) + GEN algsub(GEN al, GEN x, GEN y) + GEN algtableinit(GEN mt, GEN p) + GEN algtensor(GEN al1, GEN al2, int maxord) + GEN algtrace(GEN al, GEN x) + long algtype(GEN al) + GEN bnfgwgeneric(GEN bnf, GEN Lpr, GEN Ld, GEN pl, long var) + GEN bnrconj(GEN bnr, long i) + GEN bnrgwsearch(GEN bnr, GEN Lpr, GEN Ld, GEN pl) + void checkalg(GEN x) + void checkhasse(GEN nf, GEN hi, GEN hf, long n) + long cyclicrelfrob(GEN rnf, GEN nf2, GEN auts, GEN pr) + GEN gp_algcenter(GEN al) + GEN gp_algmultable(GEN al, GEN x) + GEN hassecoprime(GEN hi, GEN hf, long n) + GEN hassedown(GEN nf, long n, GEN hi, GEN hf) + GEN hassewedderburn(GEN hi, GEN hf, long n) + long localhasse(GEN rnf, GEN nf2, GEN cnd, GEN pl, GEN auts, GEN b, long k) + GEN nfgrunwaldwang(GEN nf0, GEN Lpr, GEN Ld, GEN pl, long var) + GEN nfgwkummer(GEN nf, GEN Lpr, GEN Ld, GEN pl, long var) + GEN extchinese(GEN nf, GEN x, GEN y, GEN pl, GEN* red) + GEN factoredextchinese(GEN nf, GEN x, GEN y, GEN pl, GEN* fa) + GEN factoredextchinesetest(GEN nf, GEN x, GEN y, GEN pl, GEN* fa, GEN data, int (*test)(GEN, GEN, GEN)) + # alglin1.c GEN F2m_F2c_gauss(GEN a, GEN b) @@ -1218,7 +1370,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RgM_invimage(GEN A, GEN B) GEN RgM_solve(GEN a, GEN b) GEN RgM_solve_realimag(GEN x, GEN y) - void RgMs_elim(GEN M, long N, GEN A, GEN *p_col, GEN *p_lin) + void RgMs_structelim(GEN M, long N, GEN A, GEN *p_col, GEN *p_lin) GEN ZM_det(GEN a) GEN ZM_detmult(GEN A) GEN ZM_gauss(GEN a, GEN b) @@ -1272,6 +1424,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN QM_ImZ_hnf(GEN x) GEN QM_ImQ_hnf(GEN x) GEN QM_charpoly_ZX(GEN M) + GEN QM_charpoly_ZX_bound(GEN M, long bit) + GEN QM_charpoly_ZX2_bound(GEN M, GEN M2, long bit) GEN ZM_charpoly(GEN x) GEN adj(GEN x) GEN adjsafe(GEN x) @@ -1306,7 +1460,9 @@ cdef extern from "sage/libs/pari/parisage.h": GEN diagonal(GEN x) GEN diagonal_shallow(GEN x) GEN extract0(GEN x, GEN l1, GEN l2) + GEN fold0(GEN f, GEN A) GEN genapply(void *E, GEN (*f)(void *E, GEN x), GEN A) + GEN genfold(void *E, GEN (*f)(void *E, GEN x, GEN y), GEN A) GEN genindexselect(void *E, long (*f)(void *E, GEN x), GEN A) GEN genselect(void *E, long (*f)(void *E, GEN x), GEN A) GEN gtomat(GEN x) @@ -1315,6 +1471,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN matmultodiagonal(GEN x, GEN y) GEN matslice0(GEN A, long x1, long x2, long y1, long y2) GEN parapply(GEN V, GEN C) + void parfor(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)) + void parforprime(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN)) GEN parselect(GEN C, GEN D, long flag) GEN select0(GEN A, GEN f, long flag) GEN shallowextract(GEN x, GEN L) @@ -1338,19 +1496,19 @@ cdef extern from "sage/libs/pari/parisage.h": GEN compile_str(char *s) GEN chartoGENstr(char c) long delete_var() - entree* fetch_named_var(char *s) long fetch_user_var(char *s) long fetch_var() + long fetch_var_higher() GEN fetch_var_value(long vx, GEN t) GEN gp_read_str(char *t) entree* install(void *f, char *name, char *code) entree* is_entry(char *s) void kill0(char *e) - long manage_var(long n, entree *ep) + void pari_var_close() void pari_var_init() long pari_var_next() long pari_var_next_temp() - void pari_var_create(entree *ep) + long pari_var_create(entree *ep) void name_var(long n, char *s) GEN readseq(char *t) GEN* safegel(GEN x, long l) @@ -1362,6 +1520,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN strtoi(char *s) GEN strtor(char *s, long prec) GEN type0(GEN x) + GEN varhigher(char *s, long v) + GEN varlower(char *s, long v) # aprcl.c @@ -1375,14 +1535,15 @@ cdef extern from "sage/libs/pari/parisage.h": void check_quaddisc_real(GEN x, long *r, char *f) long cornacchia(GEN d, GEN p, GEN *px, GEN *py) long cornacchia2(GEN d, GEN p, GEN *px, GEN *py) - GEN nucomp(GEN x, GEN y, GEN l) - GEN nudupl(GEN x, GEN l) - GEN nupow(GEN x, GEN n) + GEN nucomp(GEN x, GEN y, GEN L) + GEN nudupl(GEN x, GEN L) + GEN nupow(GEN x, GEN n, GEN L) GEN primeform(GEN x, GEN p, long prec) GEN primeform_u(GEN x, ulong p) GEN qfbcompraw(GEN x, GEN y) GEN qfbpowraw(GEN x, long n) GEN qfbred0(GEN x, long flag, GEN D, GEN isqrtD, GEN sqrtD) + GEN qfbredsl2(GEN q, GEN S) GEN qfbsolve(GEN Q, GEN n) GEN qfi(GEN x, GEN y, GEN z) GEN qfi_1(GEN x) @@ -1426,6 +1587,8 @@ cdef extern from "sage/libs/pari/parisage.h": # arith1.c ulong Fl_order(ulong a, ulong o, ulong p) + GEN Fl_powers(ulong x, long n, ulong p) + GEN Fl_powers_pre(ulong x, long n, ulong p, ulong pi) ulong Fl_powu(ulong x, ulong n, ulong p) ulong Fl_powu_pre(ulong x, ulong n, ulong p, ulong pi) ulong Fl_sqrt(ulong a, ulong p) @@ -1437,6 +1600,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Fp_log(GEN a, GEN g, GEN ord, GEN p) GEN Fp_order(GEN a, GEN o, GEN p) GEN Fp_pow(GEN a, GEN n, GEN m) + GEN Fp_powers(GEN x, long n, GEN p) GEN Fp_pows(GEN A, long k, GEN N) GEN Fp_powu(GEN x, ulong k, GEN p) GEN Fp_sqrt(GEN a, GEN p) @@ -1453,8 +1617,12 @@ cdef extern from "sage/libs/pari/parisage.h": long Z_ispow2(GEN x) long Z_ispowerall(GEN x, ulong k, GEN *pt) long Z_issquareall(GEN x, GEN *pt) + GEN Z_nv_mod(GEN P, GEN xa) GEN ZV_allpnqn(GEN x) - GEN ZV_chinese(GEN xa, GEN ya, GEN *pt_mod) + GEN ZV_chinese(GEN A, GEN P, GEN *pt_mod) + GEN ZV_chinese_tree(GEN A, GEN P, GEN tree, GEN *pt_mod) + GEN ZV_producttree(GEN xa) + GEN ZX_nv_mod_tree(GEN P, GEN xa, GEN T) long Zp_issquare(GEN a, GEN p) GEN bestappr(GEN x, GEN k) GEN bestapprPade(GEN x, long B) @@ -1503,6 +1671,7 @@ cdef extern from "sage/libs/pari/parisage.h": long logint0(GEN B, GEN y, GEN *ptq) GEN mpfact(long n) GEN mulu_interval(ulong a, ulong b) + GEN nmV_chinese(GEN A, GEN P, GEN *pt_mod) GEN odd_prime_divisors(GEN q) GEN order(GEN x) GEN pnqn(GEN x) @@ -1540,12 +1709,14 @@ cdef extern from "sage/libs/pari/parisage.h": GEN coredisc(GEN n) GEN coredisc0(GEN n, long flag) GEN coredisc2(GEN n) + long corediscs(long D, ulong *f) GEN digits(GEN N, GEN B) GEN divisors(GEN n) GEN divisorsu(ulong n) GEN factor_pn_1(GEN p, ulong n) GEN factor_pn_1_limit(GEN p, long n, ulong lim) GEN factoru_pow(ulong n) + GEN fromdigits(GEN x, GEN B) GEN fuse_Z_factor(GEN f, GEN B) GEN gen_digits(GEN x, GEN B, long n, void *E, bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r)) @@ -1654,6 +1825,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN compositum(GEN P, GEN Q) GEN compositum2(GEN P, GEN Q) GEN nfdisc(GEN x) + GEN get_modpr(GEN x) GEN indexpartial(GEN P, GEN DP) GEN modpr_genFq(GEN modpr) GEN nf_to_Fq_init(GEN nf, GEN *pr, GEN *T, GEN *p) @@ -1662,11 +1834,15 @@ cdef extern from "sage/libs/pari/parisage.h": GEN nfV_to_FqV(GEN z, GEN nf, GEN modpr) GEN nfX_to_FqX(GEN x, GEN nf, GEN modpr) GEN nfbasis(GEN x, GEN *y, GEN p) + GEN nfcompositum(GEN nf, GEN A, GEN B, long flag) void nfmaxord(nfmaxord_t *S, GEN T, long flag) GEN nfmodprinit(GEN nf, GEN pr) GEN nfreducemodpr(GEN nf, GEN x, GEN modpr) + GEN nfsplitting(GEN T, GEN D) GEN polcompositum0(GEN P, GEN Q, long flag) GEN idealprimedec(GEN nf, GEN p) + GEN idealprimedec_limit_f(GEN nf, GEN p, long f) + GEN idealprimedec_limit_norm(GEN nf, GEN p, GEN B) GEN rnfbasis(GEN bnf, GEN order) GEN rnfdedekind(GEN nf, GEN T, GEN pr, long flag) GEN rnfdet(GEN nf, GEN order) @@ -1713,6 +1889,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN nfdiv(GEN nf, GEN x, GEN y) GEN nfdiveuc(GEN nf, GEN a, GEN b) GEN nfdivrem(GEN nf, GEN a, GEN b) + GEN nfembed(GEN nf, GEN x, long k) GEN nfinv(GEN nf, GEN x) GEN nfinvmodideal(GEN nf, GEN x, GEN ideal) GEN nfmod(GEN nf, GEN a, GEN b) @@ -1739,6 +1916,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN rnfelttrace(GEN rnf, GEN x) GEN set_sign_mod_divisor(GEN nf, GEN x, GEN y, GEN idele, GEN sarch) GEN vec01_to_indices(GEN arch) + GEN vecsmall01_to_indices(GEN v) GEN vecmodii(GEN a, GEN b) GEN ideallog(GEN nf, GEN x, GEN bigideal) @@ -1759,6 +1937,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN RM_round_maxrank(GEN G) GEN ZM_famat_limit(GEN fa, GEN limit) + GEN famat_Z_gcd(GEN M, GEN n) GEN famat_inv(GEN f) GEN famat_inv_shallow(GEN f) GEN famat_makecoprime(GEN nf, GEN g, GEN e, GEN pr, GEN prk, GEN EX) @@ -1798,6 +1977,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN idealhnf0(GEN nf, GEN a, GEN b) GEN idealintersect(GEN nf, GEN x, GEN y) GEN idealinv(GEN nf, GEN ix) + GEN idealinv_HNF(GEN nf, GEN I) GEN idealred0(GEN nf, GEN I, GEN vdir) GEN idealmul(GEN nf, GEN ix, GEN iy) GEN idealmul0(GEN nf, GEN ix, GEN iy, long flag) @@ -1821,12 +2001,14 @@ cdef extern from "sage/libs/pari/parisage.h": GEN nfdetint(GEN nf, GEN pseudo) GEN nfdivmodpr(GEN nf, GEN x, GEN y, GEN modpr) GEN nfhnf(GEN nf, GEN x) + GEN nfhnf0(GEN nf, GEN x, long flag) GEN nfhnfmod(GEN nf, GEN x, GEN d) GEN nfkermodpr(GEN nf, GEN x, GEN modpr) GEN nfmulmodpr(GEN nf, GEN x, GEN y, GEN modpr) GEN nfpowmodpr(GEN nf, GEN x, GEN k, GEN modpr) GEN nfreduce(GEN nf, GEN x, GEN ideal) GEN nfsnf(GEN nf, GEN x) + GEN nfsnf0(GEN nf, GEN x, long flag) GEN nfsolvemodpr(GEN nf, GEN a, GEN b, GEN modpr) GEN to_famat(GEN x, GEN y) GEN to_famat_shallow(GEN x, GEN y) @@ -1884,6 +2066,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN gen_powu_i(GEN x, ulong n, void *E, GEN (*sqr)(void*, GEN), GEN (*mul)(void*, GEN, GEN)) GEN gen_powu_fold(GEN x, ulong n, void *E, GEN (*sqr)(void*, GEN), GEN (*msqr)(void*, GEN)) GEN gen_powu_fold_i(GEN x, ulong n, void *E, GEN (*sqr)(void*, GEN), GEN (*msqr)(void*, GEN)) + GEN gen_product(GEN x, void *data, GEN (*mul)(void*, GEN, GEN)) # bibli1.c @@ -1909,7 +2092,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN qfrep0(GEN a, GEN borne, long flag) GEN qfminim0(GEN a, GEN borne, GEN stockmax, long flag, long prec) GEN seralgdep(GEN s, long p, long r) - GEN zncoppersmith(GEN P0, GEN N, GEN X, GEN B) + GEN zncoppersmith(GEN P0, GEN N, GEN X, GEN B) # bibli2.c @@ -2112,7 +2295,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN default0(char *a, char *b) long getrealprecision() - int pari_is_default(char *s) + entree *pari_is_default(char *s) GEN sd_TeXstyle(char *v, long flag) GEN sd_colors(char *v, long flag) GEN sd_compatible(char *v, long flag) @@ -2149,6 +2332,39 @@ cdef extern from "sage/libs/pari/parisage.h": GEN setdefault(char *s, char *v, long flag) long setrealprecision(long n, long *prec) + # gplib.c + GEN sd_breakloop(char *v, long flag) + GEN sd_echo(char *v, long flag) + GEN sd_graphcolormap(char *v, long flag) + GEN sd_graphcolors(char *v, long flag) + GEN sd_help(char *v, long flag) + GEN sd_histfile(char *v, long flag) + GEN sd_lines(char *v, long flag) + GEN sd_linewrap(char *v, long flag) + GEN sd_prompt(char *v, long flag) + GEN sd_prompt_cont(char *v, long flag) + GEN sd_psfile(char *v, long flag) + GEN sd_readline(char *v, long flag) + GEN sd_recover(char *v, long flag) + GEN sd_timer(char *v, long flag) + void pari_hit_return() + void gp_load_gprc() + int gp_meta(char *buf, int ismain) + void pari_center(char *s) + void pari_print_version() + char *gp_format_time(long delay) + char *gp_format_prompt(char *p) + void pari_alarm(long s) + GEN gp_alarm(long s, GEN code) + GEN gp_input() + void gp_allocatemem(GEN z) + int gp_handle_exception(long numerr) + void gp_alarm_handler(int sig) + void gp_sigint_fun() + void gp_help(char *s, long flag) + void gp_echo_and_log(char *prompt, char *s) + void print_fun_list(char **list, long nbli) + # ellanal.c GEN ellanalyticrank(GEN e, GEN eps, long prec) @@ -2165,9 +2381,13 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ellsearchcurve(GEN name) void forell(void *E, long call(void*, GEN), long a, long b) - # elliptic.c + # ellfromeqn.c - extern int t_ELL_Rg, t_ELL_Q, t_ELL_Qp, t_ELL_Fp, t_ELL_Fq, t_ELL_NF + GEN ellfromeqn(GEN s) + + # elliptic.c + long ellQ_get_CM(GEN e) + int ell_is_integral(GEN E) GEN ellbasechar(GEN E) GEN akell(GEN e, GEN n) GEN anell(GEN e, long n) @@ -2180,9 +2400,12 @@ cdef extern from "sage/libs/pari/parisage.h": void checkellisog(GEN v) void checkellpt(GEN z) void checkell5(GEN e) + GEN ec_bmodel(GEN e) GEN ec_f_evalx(GEN E, GEN x) + GEN ec_h_evalx(GEN e, GEN x) GEN ec_dFdx_evalQ(GEN E, GEN Q) GEN ec_dFdy_evalQ(GEN E, GEN Q) + GEN ec_dmFdy_evalQ(GEN e, GEN Q) GEN ec_2divpol_evalx(GEN E, GEN x) GEN ec_half_deriv_2divpol_evalx(GEN E, GEN x) GEN ellanal_globalred(GEN e, GEN *gr) @@ -2200,6 +2423,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ellR_roots(GEN E, long prec) GEN elladd(GEN e, GEN z1, GEN z2) GEN ellap(GEN e, GEN p) + long ellap_CM_fast(GEN E, ulong p, long CM) GEN ellcard(GEN E, GEN p) GEN ellchangecurve(GEN e, GEN ch) GEN ellchangeinvert(GEN w) @@ -2228,7 +2452,10 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ellheightmatrix(GEN E, GEN x, long n) GEN ellheightoo(GEN e, GEN z, long prec) GEN ellinit(GEN x, GEN p, long prec) + GEN ellintegralmodel(GEN e, GEN *pv) GEN ellisoncurve(GEN e, GEN z) + int ellissupersingular(GEN x, GEN p) + int elljissupersingular(GEN x) GEN elllseries(GEN e, GEN s, GEN A, long prec) GEN elllocalred(GEN e, GEN p1) GEN elllog(GEN e, GEN a, GEN g, GEN o) @@ -2237,6 +2464,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ellnonsingularmultiple(GEN e, GEN P) GEN ellneg(GEN e, GEN z) GEN ellorder(GEN e, GEN p, GEN o) + long ellorder_Q(GEN E, GEN P) GEN ellordinate(GEN e, GEN x, long prec) GEN ellpadicfrobenius(GEN E, ulong p, long n) GEN ellpadicheight(GEN e, GEN p, long n, GEN P) @@ -2258,13 +2486,19 @@ cdef extern from "sage/libs/pari/parisage.h": GEN ellwp(GEN w, GEN z, long prec) GEN ellwp0(GEN w, GEN z, long flag, long prec) GEN ellwpseries(GEN e, long v, long PRECDL) + GEN ellxn(GEN e, long n, long v) GEN ellzeta(GEN om, GEN z, long prec) GEN expIxy(GEN x, GEN y, long prec) int oncurve(GEN e, GEN z) GEN orderell(GEN e, GEN p) GEN pointell(GEN e, GEN z, long prec) + GEN point_to_a4a6(GEN E, GEN P, GEN p, GEN *pa4) + GEN point_to_a4a6_Fl(GEN E, GEN P, ulong p, ulong *pa4) GEN zell(GEN e, GEN z, long prec) + # elltors.c + long ellisdivisible(GEN E, GEN P, GEN n, GEN *Q) + # ellpadicL.c GEN ellpadicL(GEN E, GEN p, long n, long r, GEN D, GEN C) @@ -2282,6 +2516,11 @@ cdef extern from "sage/libs/pari/parisage.h": # es.c + GEN externstr(char *cmd) + char *gp_filter(char *s) + GEN gpextern(char *cmd) + void gpsystem(char *s) + GEN readstr(char *s) GEN GENtoGENstr_nospace(GEN x) GEN GENtoGENstr(GEN x) char* GENtoTeXstr(GEN x) @@ -2353,7 +2592,6 @@ cdef extern from "sage/libs/pari/parisage.h": void out_term_color(PariOUT *out, long c) void out_vprintf(PariOUT *out, char *fmt, va_list ap) char* pari_sprint0(char *msg, GEN g, long flag) - extern int f_RAW, f_PRETTYMAT, f_PRETTY, f_TEX void print0(GEN g, long flag) void print1(GEN g) void printf0(char *fmt, GEN args) @@ -2379,13 +2617,14 @@ cdef extern from "sage/libs/pari/parisage.h": # eval.c - extern int br_NONE, br_BREAK, br_NEXT, br_MULTINEXT, br_RETURN void bincopy_relink(GEN C, GEN vi) GEN break0(long n) GEN closure_callgen1(GEN C, GEN x) + GEN closure_callgen1prec(GEN C, GEN x, long prec) GEN closure_callgen2(GEN C, GEN x, GEN y) GEN closure_callgenall(GEN C, long n, ...) GEN closure_callgenvec(GEN C, GEN args) + GEN closure_callgenvecprec(GEN C, GEN args, long prec) void closure_callvoid1(GEN C, GEN x) long closure_context(long start, long level) void closure_disassemble(GEN n) @@ -2398,20 +2637,28 @@ cdef extern from "sage/libs/pari/parisage.h": GEN closure_trapgen(GEN C, long numerr) GEN copybin_unlink(GEN C) GEN get_lex(long vn) + long get_localprec() GEN gp_call(void *E, GEN x) + GEN gp_callprec(void *E, GEN x, long prec) + GEN gp_call2(void *E, GEN x, GEN y) long gp_callbool(void *E, GEN x) long gp_callvoid(void *E, GEN x) GEN gp_eval(void *E, GEN x) long gp_evalbool(void *E, GEN x) + GEN gp_evalprec(void *E, GEN x, long prec) GEN gp_evalupto(void *E, GEN x) long gp_evalvoid(void *E, GEN x) + void localprec(long p) long loop_break() GEN next0(long n) GEN pareval(GEN C) + GEN pari_self() GEN parsum(GEN a, GEN b, GEN code, GEN x) GEN parvector(long n, GEN code) void pop_lex(long n) + void pop_localprec() void push_lex(GEN a, GEN C) + void push_localprec(long p) GEN return0(GEN x) void set_lex(long vn, GEN x) @@ -2596,9 +2843,13 @@ cdef extern from "sage/libs/pari/parisage.h": GEN gtolist(GEN x) long gtolong(GEN x) int lexcmp(GEN x, GEN y) + GEN listcreate_typ(long t) + GEN listcreate() GEN listinsert(GEN list, GEN object, long index) void listpop(GEN L, long index) + void listpop0(GEN L, long index) GEN listput(GEN list, GEN object, long index) + GEN listput0(GEN list, GEN object, long index) void listsort(GEN list, long flag) GEN matsize(GEN x) GEN mklistcopy(GEN x) @@ -2742,6 +2993,7 @@ cdef extern from "sage/libs/pari/parisage.h": long poldegree(GEN x, long v) long RgX_degree(GEN x, long v) GEN poleval(GEN x, GEN y) + GEN RgX_cxeval(GEN T, GEN u, GEN ui) GEN pollead(GEN x, long v) long precision(GEN x) GEN precision0(GEN x, long n) @@ -2766,6 +3018,10 @@ cdef extern from "sage/libs/pari/parisage.h": GEN toser_i(GEN x) GEN trunc0(GEN x, GEN *pte) GEN uu32toi(ulong a, ulong b) + GEN vars_sort_inplace(GEN z) + GEN vars_to_RgXV(GEN h) + GEN variables_vecsmall(GEN x) + GEN variables_vec(GEN x) # genus2red.c @@ -2778,11 +3034,17 @@ cdef extern from "sage/libs/pari/parisage.h": # hash.c + hashtable *hash_create_ulong(ulong s, long stack) + hashtable *hash_create_str(ulong s, long stack) hashtable *hash_create(ulong minsize, ulong (*hash)(void*), int (*eq)(void*, void*), int use_stack) void hash_insert(hashtable *h, void *k, void *v) + GEN hash_keys(hashtable *h) + GEN hash_values(hashtable *h) hashentry *hash_search(hashtable *h, void *k) hashentry *hash_search2(hashtable *h, void *k, ulong hash) + hashentry *hash_select(hashtable *h, void *k, void *E, int(*select)(void *, hashentry *)) hashentry *hash_remove(hashtable *h, void *k) + hashentry *hash_remove_select(hashtable *h, void *k, void *E, int (*select)(void*, hashentry*)) void hash_destroy(hashtable *h) ulong hash_str(char *str) ulong hash_str2(char *s) @@ -2791,7 +3053,7 @@ cdef extern from "sage/libs/pari/parisage.h": # hyperell.c GEN hyperellpadicfrobenius(GEN x, ulong p, long e) - GEN hyperellzeta(GEN x) + GEN hyperellcharpoly(GEN x) GEN nfhyperellpadicfrobenius(GEN H, GEN T, ulong p, long n) # hnf_snf.c @@ -2916,7 +3178,8 @@ cdef extern from "sage/libs/pari/parisage.h": GEN obj_check(GEN S, long K) GEN obj_checkbuild(GEN S, long tag, GEN (*build)(GEN)) GEN obj_checkbuild_padicprec(GEN S, long tag, GEN (*build)(GEN, long), long prec) - GEN obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN, long), long prec) + GEN obj_checkbuild_realprec(GEN S, long tag, GEN (*build)(GEN, long), long prec) + GEN obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN, long), long (*pr)(GEN), long prec) void obj_free(GEN S) GEN obj_init(long d, long n) GEN obj_insert(GEN S, long K, GEN O) @@ -2924,9 +3187,9 @@ cdef extern from "sage/libs/pari/parisage.h": void pari_add_function(entree *ep) void pari_add_module(entree *ep) void pari_add_defaults_module(entree *ep) - void pari_add_oldmodule(entree *ep) void pari_close() void pari_close_opts(ulong init_opts) + GEN pari_compile_str(char *lex) int pari_daemon() void pari_err(int numerr, ...) GEN pari_err_last() @@ -2961,22 +3224,19 @@ cdef extern from "sage/libs/pari/parisage.h": # intnum.c + GEN contfraceval(GEN CF, GEN t, long nlim) + GEN contfracinit(GEN M, long lim) GEN intcirc(void *E, GEN (*eval) (void *, GEN), GEN a, GEN R, GEN tab, long prec) - GEN intfouriercos(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, GEN x, GEN tab, long prec) - GEN intfourierexp(void *E, GEN (*eval)(void *, GEN), GEN a, GEN b, GEN x, GEN tab, long prec) - GEN intfouriersin(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, GEN x, GEN tab, long prec) - GEN intfuncinit(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, long m, long flag, long prec) - GEN intlaplaceinv(void *E, GEN (*eval) (void *, GEN), GEN sig, GEN x, GEN tab, long prec) - GEN intmellininv(void *E, GEN (*eval) (void *, GEN), GEN sig, GEN x, GEN tab, long prec) - GEN intmellininvshort(GEN sig, GEN x, GEN tab, long prec) + GEN intfuncinit(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, long m, long prec) GEN intnum(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, GEN tab, long prec) + GEN intnumgauss(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN tab, long prec) + GEN intnumgaussinit(long n, long prec) GEN intnuminit(GEN a, GEN b, long m, long prec) - GEN intnuminitgen(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, long m, long flext, long prec) GEN intnumromb(void *E, GEN (*eval) (void *, GEN), GEN a, GEN b, long flag, long prec) - long intnumstep(long prec) - GEN sumnum(void *E, GEN (*f) (void *, GEN), GEN a, GEN sig, GEN tab, long flag, long prec) - GEN sumnumalt(void *E, GEN (*f) (void *, GEN), GEN a, GEN s, GEN tab, long flag, long prec) - GEN sumnuminit(GEN sig, long m, long sgn, long prec) + GEN sumnum(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec) + GEN sumnuminit(GEN fast, long prec) + GEN sumnummon(void *E, GEN (*eval)(void*, GEN), GEN a, GEN tab, long prec) + GEN sumnummoninit(GEN asymp, GEN w, GEN n0, long prec) # krasner.c @@ -3007,6 +3267,28 @@ cdef extern from "sage/libs/pari/parisage.h": GEN qflll0(GEN x, long flag) GEN qflllgram0(GEN x, long flag) + # map.c + + GEN gtomap(GEN M) + void mapdelete(GEN T, GEN a) + GEN mapdomain(GEN T) + GEN mapdomain_shallow(GEN T) + GEN mapget(GEN T, GEN a) + int mapisdefined(GEN T, GEN a, GEN *pt_z) + void mapput(GEN T, GEN a, GEN b) + GEN maptomat(GEN T) + GEN maptomat_shallow(GEN T) + + # mellininv.c + + GEN gammamellininv(GEN Vga, GEN s, long m, long prec) + GEN gammamellininv_bitprec(GEN Vga, GEN s, long m, long bitprec) + GEN gammamellininvasymp(GEN Vga, long nlimmax, long m) + GEN gammamellininvinit(GEN Vga, long m, long prec) + GEN gammamellininvinit_bitprec(GEN Vga, long m, long bitprec) + GEN gammamellininvrt(GEN K, GEN x, long prec) + GEN gammamellininvrt_bitprec(GEN K, GEN s, long bitprec) + # members.c GEN member_a1(GEN x) @@ -3087,6 +3369,7 @@ cdef extern from "sage/libs/pari/parisage.h": void affrr(GEN x, GEN y) GEN bezout(GEN a, GEN b, GEN *u, GEN *v) long cbezout(long a, long b, long *uu, long *vv) + GEN cbrtr_abs(GEN x) int cmpii(GEN x, GEN y) int cmprr(GEN x, GEN y) long dblexpo(double x) @@ -3158,6 +3441,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN nffactormod(GEN nf, GEN pol, GEN pr) GEN nfgcd(GEN P, GEN Q, GEN nf, GEN den) GEN nfgcd_all(GEN P, GEN Q, GEN T, GEN den, GEN *Pnew) + int nfissquarefree(GEN nf, GEN x) GEN nfroots(GEN nf, GEN pol) GEN polfnf(GEN a, GEN t) GEN rootsof1(GEN x) @@ -3220,7 +3504,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN vecperm_orbits(GEN v, long n) GEN vec_insert(GEN v, long n, GEN x) int vec_is1to1(GEN v) - int vec_is(GEN v) + int vec_isconst(GEN v) long vecsmall_duplicate(GEN x) long vecsmall_duplicate_sorted(GEN x) GEN vecsmall_indexsort(GEN V) @@ -3285,8 +3569,6 @@ cdef extern from "sage/libs/pari/parisage.h": GEN centermodii(GEN x, GEN p, GEN po2) GEN content(GEN x) GEN deg1_from_roots(GEN L, long v) - GEN divide_conquer_assoc(GEN x, void *data, GEN (*mul)(void*, GEN, GEN)) - GEN divide_conquer_prod(GEN x, GEN (*mul)(GEN, GEN)) GEN factor(GEN x) GEN factor0(GEN x, long flag) GEN factorback(GEN fa) @@ -3517,8 +3799,9 @@ cdef extern from "sage/libs/pari/parisage.h": # sumiter.c - GEN derivnum(void *E, GEN (*eval)(void *, GEN), GEN x, long prec) - GEN derivfun(void *E, GEN (*eval)(void *, GEN), GEN x, long prec) + GEN asympnum(void *E, GEN (*f)(void *, GEN, long), long muli, GEN alpha, long prec) + GEN derivnum(void *E, GEN (*eval)(void *, GEN, long prec), GEN x, long prec) + GEN derivfun(void *E, GEN (*eval)(void *, GEN, long prec), GEN x, long prec) GEN direuler(void *E, GEN (*eval)(void *, GEN), GEN ga, GEN gb, GEN c) int forcomposite_init(forcomposite_t *C, GEN a, GEN b) GEN forcomposite_next(forcomposite_t *C) @@ -3526,6 +3809,7 @@ cdef extern from "sage/libs/pari/parisage.h": int forprime_init(forprime_t *T, GEN a, GEN b) int forvec_init(forvec_t *T, GEN x, long flag) GEN forvec_next(forvec_t *T) + GEN limitnum(void *E, GEN (*f)(void *, GEN, long), long muli, GEN alpha, long prec) GEN polzag(long n, long m) GEN prodeuler(void *E, GEN (*eval)(void *, GEN), GEN ga, GEN gb, long prec) GEN prodinf(void *E, GEN (*eval)(void *, GEN), GEN a, long prec) @@ -3562,10 +3846,10 @@ cdef extern from "sage/libs/pari/parisage.h": GEN Zn_sqrt(GEN x, GEN n) GEN Zp_teichmuller(GEN x, GEN p, long n, GEN q) GEN agm(GEN x, GEN y, long prec) - GEN catalan(long prec) - GEN euler(long prec) - GEN log2(long prec) - GEN pi(long prec) + GEN constcatalan(long prec) + GEN consteuler(long prec) + GEN constlog2(long prec) + GEN constpi(long prec) GEN cxexpm1(GEN z, long prec) GEN expIr(GEN x) GEN exp1r_abs(GEN x) @@ -3578,6 +3862,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN gpowers(GEN x, long n) GEN gpowgs(GEN x, long n) GEN gsin(GEN x, long prec) + GEN gsinc(GEN x, long prec) void gsincos(GEN x, GEN *s, GEN *c, long prec) GEN gsqrt(GEN x, long prec) GEN gsqrtn(GEN x, GEN n, GEN *zetan, long prec) @@ -3638,31 +3923,33 @@ cdef extern from "sage/libs/pari/parisage.h": # trans3.c + double dblmodulus(GEN x) GEN dilog(GEN x, long prec) GEN eint1(GEN x, long prec) GEN eta(GEN x, long prec) GEN eta0(GEN x, long flag, long prec) GEN gerfc(GEN x, long prec) + GEN glambertW(GEN y, long prec) GEN gpolylog(long m, GEN x, long prec) GEN gzeta(GEN x, long prec) + GEN hbessel1(GEN n, GEN z, long prec) + GEN hbessel2(GEN n, GEN z, long prec) GEN hyperu(GEN a, GEN b, GEN gx, long prec) + GEN ibessel(GEN n, GEN z, long prec) GEN incgam(GEN a, GEN x, long prec) GEN incgam0(GEN a, GEN x, GEN z, long prec) GEN incgamc(GEN a, GEN x, long prec) - GEN hbessel1(GEN n, GEN z, long prec) - GEN hbessel2(GEN n, GEN z, long prec) - GEN ibessel(GEN n, GEN z, long prec) GEN jbessel(GEN n, GEN z, long prec) GEN jbesselh(GEN n, GEN z, long prec) + GEN jell(GEN x, long prec) + GEN kbessel(GEN nu, GEN gx, long prec) GEN mpeint1(GEN x, GEN expx) GEN mplambertW(GEN y) GEN mpveceint1(GEN C, GEN eC, long n) GEN nbessel(GEN n, GEN z, long prec) - GEN jell(GEN x, long prec) - GEN kbessel(GEN nu, GEN gx, long prec) GEN polylog0(long m, GEN x, long flag, long prec) - GEN sumdedekind_coprime(GEN h, GEN k) GEN sumdedekind(GEN h, GEN k) + GEN sumdedekind_coprime(GEN h, GEN k) GEN szeta(long x, long prec) GEN theta(GEN q, GEN z, long prec) GEN thetanullk(GEN q, long k, long prec) @@ -3675,28 +3962,34 @@ cdef extern from "sage/libs/pari/parisage.h": GEN weberf(GEN x, long prec) GEN weberf1(GEN x, long prec) GEN weberf2(GEN x, long prec) - GEN glambertW(GEN y, long prec) + GEN zetaBorweinRecycled(long s, long h, long N, long prec) # modsym.c - GEN Cuspidal_subspace(GEN W) - GEN Eisenstein_subspace(GEN W) GEN Eisenstein_symbol(GEN W, GEN c) - GEN Q_xpm(GEN E, GEN c) - GEN Qevproj_init(GEN M) + GEN Q_xpm(GEN W, GEN xpm, GEN c) GEN Qevproj_apply(GEN T, GEN pro) GEN Qevproj_apply_vecei(GEN T, GEN pro, long k) + GEN Qevproj_init(GEN M) GEN RgX_act_Gl2Q(GEN g, long k) GEN RgX_act_ZGl2Q(GEN z, long k) - GEN ellsym(GEN E, long signe) - GEN modsymbAtkinLehner(GEN W, GEN Q) - GEN modsymbHecke(GEN W, ulong p) - GEN modsymbSigma(GEN W) - GEN modsymblog(GEN W, GEN path) + void checkms(GEN W) + GEN msfromell(GEN E, long signe) + GEN msatkinlehner(GEN W, long Q, GEN) + GEN mscuspidal(GEN W, long flag) + GEN mseisenstein(GEN W) + GEN mseval(GEN W, GEN s, GEN p) + GEN mshecke(GEN W, long p, GEN H) GEN msinit(GEN N, GEN k, long sign) - GEN new_subspace(GEN W) - GEN qexpansion(GEN W, GEN proV, long B) - GEN simple_subspaces(GEN W, GEN H) - GEN xpm(GEN E, GEN a, GEN b) + long msissymbol(GEN W, GEN s) + GEN mspathgens(GEN W) + GEN mspathlog(GEN W, GEN path) + GEN msnew(GEN W) + GEN msstar(GEN W, GEN) + GEN msqexpansion(GEN W, GEN proV, ulong B) + GEN mssplit(GEN W, GEN H) + + # zetamult.c + GEN zetamult(GEN avec, long prec) # level1.h @@ -3704,6 +3997,7 @@ cdef extern from "sage/libs/pari/parisage.h": long Fl_center(ulong u, ulong p, ulong ps2) ulong Fl_div(ulong a, ulong b, ulong p) ulong Fl_double(ulong a, ulong p) + ulong Fl_ellj_pre(ulong a4, ulong a6, ulong p, ulong pi) ulong Fl_halve(ulong y, ulong p) ulong Fl_mul(ulong a, ulong b, ulong p) ulong Fl_mul_pre(ulong a, ulong b, ulong p, ulong pi) @@ -3895,7 +4189,7 @@ cdef extern from "sage/libs/pari/parisage.h": ulong udiviu_rem(GEN n, ulong d, ulong *r) ulong udivuu_rem(ulong x, ulong y, ulong *r) void setabssign(GEN x) - void shift_left(GEN z2, GEN z1, long min, long M, ulong f, ulong sh) + void shift_left(GEN z2, GEN z1, long min, long M, ulong f, ulong sh) void shift_right(GEN z2, GEN z1, long min, long M, ulong f, ulong sh) ulong shiftl(ulong x, ulong y) ulong shiftlr(ulong x, ulong y) @@ -3934,6 +4228,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN truedivis(GEN a, long b) GEN truedivsi(long a, GEN b) ulong udivui_rem(ulong x, GEN y, ulong *rem) + ulong umodsu(long x, ulong y) ulong umodui(ulong x, GEN y) GEN utoi(ulong x) GEN utoineg(ulong x) @@ -3942,6 +4237,7 @@ cdef extern from "sage/libs/pari/parisage.h": GEN uutoi(ulong x, ulong y) GEN uutoineg(ulong x, ulong y) long vali(GEN x) + int varncmp(long x, long y) cdef extern from "sage/libs/pari/parisage.h": GEN set_gel(GEN x, long n, GEN z) # gel(x,n) = z @@ -3967,7 +4263,7 @@ cdef extern from 'pari/paripriv.h': struct gp_data: pariout_t *fmt unsigned long flags - + extern gp_data* GP_DATA cdef extern from 'pari/anal.h': diff --git a/src/sage/libs/pari/gen.pyx b/src/sage/libs/pari/gen.pyx index b64c0def73a..4b8db5cb28a 100644 --- a/src/sage/libs/pari/gen.pyx +++ b/src/sage/libs/pari/gen.pyx @@ -8259,11 +8259,14 @@ cdef class gen(gen_auto): INPUT: - ``self`` -- a quadratic form + - ``b`` -- a bound on vector norm (finds minimal non-zero - vectors if b=0) + vectors if b is ``None``) + - ``m`` -- maximum number of vectors to return. If ``None`` (default), return all vectors of norm at most B - - flag (optional) -- + + - ``flag`` (optional) -- - 0: default; - 1: return only the first minimal vector found (ignore ``max``); @@ -8303,7 +8306,7 @@ cdef class gen(gen_auto): All vectors of minimal norm:: - sage: pari(A).qfminim(0).python() + sage: pari(A).qfminim().python() [ [-5 -2 1] [ 1 1 0] @@ -9248,7 +9251,7 @@ cdef class gen(gen_auto): With flag=1, compute the pair P(z) and P'(z):: sage: E.ellwp(1, flag=1) - [13.9658695257485, 50.5619893875144] + [13.9658695257485, 50.5619300880073] """ cdef gen t0 = objtogen(z) cdef GEN g0 = t0.g diff --git a/src/sage/libs/pari/pari_instance.pyx b/src/sage/libs/pari/pari_instance.pyx index ac434b555b1..16e2ca1699f 100644 --- a/src/sage/libs/pari/pari_instance.pyx +++ b/src/sage/libs/pari/pari_instance.pyx @@ -33,7 +33,7 @@ EXAMPLES:: sage: pari('5! + 10/x') (120*x + 10)/x sage: pari('intnum(x=0,13,sin(x)+sin(x^2) + x)') - 85.1885681951527 + 84.1818153922297 sage: f = pari('x^3-1') sage: v = f.factor(); v [x - 1, 1; x^2 + x + 1, 1] From da46c953bd22e80790ec6437cfe529484c858dec Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 30 Apr 2015 12:03:11 +0200 Subject: [PATCH 604/665] Auto-generated PARI files should depend on decl.pxi --- src/Makefile | 3 ++- src/sage_setup/autogen/pari/generator.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index f060d1b5610..f7e12daaf43 100644 --- a/src/Makefile +++ b/src/Makefile @@ -24,7 +24,8 @@ clean: # Auto-generated files -sage/libs/pari/auto_gen.pxi: $(SAGE_LOCAL)/share/pari/pari.desc sage_setup/autogen/pari/*.py +sage/libs/pari/auto_gen.pxi: $(SAGE_LOCAL)/share/pari/pari.desc \ + sage/libs/pari/decl.pxi sage_setup/autogen/pari/*.py python -c "from sage_setup.autogen.pari import rebuild; rebuild()" sage/ext/interpreters/__init__.py: sage_setup/autogen/interpreters.py diff --git a/src/sage_setup/autogen/pari/generator.py b/src/sage_setup/autogen/pari/generator.py index 82227e0a2ba..7aa99903142 100644 --- a/src/sage_setup/autogen/pari/generator.py +++ b/src/sage_setup/autogen/pari/generator.py @@ -48,6 +48,7 @@ function_re = re.compile(r"^[A-Za-z][A-Za-z0-9_]*$") function_blacklist = {"O", # O(p^e) needs special parser support "alias", # Not needed and difficult documentation + "listcreate", # "redundant and obsolete" according to PARI } class PariFunctionGenerator(object): From 3dbae9064bd5e251500dca66ca26d6acdb1318c5 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Thu, 30 Apr 2015 06:54:46 -0400 Subject: [PATCH 605/665] limit output aspect ratio of graphics --- src/sage/plot/graphics.py | 66 ++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index a19ef6a9b65..1384f7a4c87 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -29,6 +29,7 @@ #***************************************************************************** import os +from math import isnan import sage.misc.misc from sage.misc.html import html from sage.misc.temporary_file import tmp_filename @@ -2082,7 +2083,7 @@ def ymax(self, ymax=None): def get_minmax_data(self): - """ + r""" Return a dictionary whose keys give the xmin, xmax, ymin, and ymax data for this graphic. @@ -2105,6 +2106,21 @@ def get_minmax_data(self): sage: g.ymax(10) sage: list(sorted(g.get_minmax_data().items())) [('xmax', 3.0), ('xmin', -1.0), ('ymax', 2.0), ('ymin', 1.0)] + + The width/height ratio (in output units, after factoring in the + chosen aspect ratio) of the plot is limited to `10^{-15}\dots + 10^{15}`, otherwise floating point errors cause problems in + matplotlib:: + + sage: l = line([(1e-19,-1), (-1e-19,+1)], aspect_ratio=1.0) + sage: l.get_minmax_data() + {'xmax': 1.00010000000000e-15, + 'xmin': -9.99900000000000e-16, + 'ymax': 1.0, + 'ymin': -1.0} + sage: l = line([(0,0), (1,1)], aspect_ratio=1e19) + sage: l.get_minmax_data() + {'xmax': 5000.50000000000, 'xmin': -4999.50000000000, 'ymax': 1.0, 'ymin': 0.0} """ objects = self._objects if objects: @@ -2113,15 +2129,13 @@ def get_minmax_data(self): xmax = max(d['xmax'] for d in minmax_data) ymin = min(d['ymin'] for d in minmax_data) ymax = max(d['ymax'] for d in minmax_data) - # check for NaN's: weird thing -- only way I know to check if a float - # is a NaN is to check if it is not equal to itself. - if xmin!=xmin: + if isnan(xmin): xmin=0; sage.misc.misc.verbose("xmin was NaN (setting to 0)", level=0) - if xmax!=xmax: + if isnan(xmax): xmax=0; sage.misc.misc.verbose("xmax was NaN (setting to 0)", level=0) - if ymin!=ymin: + if isnan(ymin): ymin=0; sage.misc.misc.verbose("ymin was NaN (setting to 0)", level=0) - if ymax!=ymax: + if isnan(ymax): ymax=0; sage.misc.misc.verbose("ymax was NaN (setting to 0)", level=0) else: xmin = xmax = ymin = ymax = 0 @@ -2132,6 +2146,44 @@ def get_minmax_data(self): if ymin == ymax: ymin -= 1 ymax += 1 + return self._limit_output_aspect_ratio(xmin, xmax, ymin, ymax) + + def _limit_output_aspect_ratio(self, xmin, xmax, ymin, ymax): + """ + Private helper function for :meth:`get_minmax_data` + + EXAMPLES:: + + sage: l = line([(0,0), (1,1)], aspect_ratio=1.0) + sage: l._limit_output_aspect_ratio(1, 2, 1e19, 3) + {'xmax': -4999.50000000000, + 'xmin': 5000.50000000000, + 'ymax': 3, + 'ymin': 1.00000000000000e19} + sage: l._limit_output_aspect_ratio(1, 2, 3, 1e19) + {'xmax': 5000.50000000000, + 'xmin': -4999.50000000000, + 'ymax': 1.00000000000000e19, + 'ymin': 3} + sage: l = line([(0,0), (1,1)], aspect_ratio=1e16) + sage: l._limit_output_aspect_ratio(0, 1, 2, 3) + {'xmax': 5.50000000000000, 'xmin': -4.50000000000000, 'ymax': 3, 'ymin': 2} + """ + aspect_ratio = self.aspect_ratio() + if aspect_ratio != 'automatic': + width = xmax - xmin + height = ymax - ymin + output_aspect = width/height/aspect_ratio + if output_aspect > 1e15: + height = 1e15 * width / aspect_ratio + ycenter = (ymax - ymin) / 2 + ymin = ycenter - height/2 + ymax = ycenter + height/2 + if output_aspect < 1e-15: + width = 1e-15 * height * aspect_ratio + xcenter = (xmax - xmin) / 2 + xmin = xcenter - width/2 + xmax = xcenter + width/2 return {'xmin':xmin, 'xmax':xmax, 'ymin':ymin, 'ymax':ymax} def _matplotlib_tick_formatter(self, subplot, base=(10, 10), From 23a01103840dd8dd37197f7a18c9b1ac8635bd47 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 30 Apr 2015 13:42:56 +0200 Subject: [PATCH 606/665] Fix call to PARI qfminim() in shortest_vector() --- src/sage/modules/free_module_integer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index 3d99ae80951..a57b3a09df7 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -624,7 +624,7 @@ def shortest_vector(self, update_reduced_basis=True, algorithm="fplll", *args, * B = self.reduced_basis.LLL() qf = B*B.transpose() - count, length, vectors = qf._pari_().qfminim(0, None) + count, length, vectors = qf._pari_().qfminim() v = vectors.python().columns()[0] w = v*B elif algorithm == "fplll": From 46f4f54eca326eae1b2a602c1168361a4463269e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 30 Apr 2015 13:45:24 +0200 Subject: [PATCH 607/665] 18336: moved default implementation of algebra_generators to MagmaticAlgebras.WithBasis + proofread doc --- src/sage/categories/algebras_with_basis.py | 22 ------------------ src/sage/categories/magmatic_algebras.py | 26 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index a6e93032ab3..8a4668edf1e 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -193,28 +193,6 @@ def _product_from_combinatorial_algebra_multiply(self,left,right): # tester.assert_(self.product is not None) # could check that self.product is in Hom( self x self, self) - def algebra_generators(self): - r""" - Return algebra generators for this algebra, namely its basis. - - OUTPUT: - - - A family that generate self - - EXAMPLES:: - - sage: D4 = DescentAlgebra(QQ, 4).B() - sage: D4.algebra_generators() - Lazy family (Term map from Compositions of 4 to Descent algebra - of 4 over Rational Field in the subset basis(i))_{i in - Compositions of 4} - sage: R. = ZZ[] - sage: P = PartitionAlgebra(1, x, R) - sage: P.algebra_generators() - Finite family {{{-1, 1}}: P[{{-1, 1}}], {{-1}, {1}}: P[{{-1}, {1}}]} - """ - return self.basis() - class ElementMethods: def __invert__(self): diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index 3b66073de53..d0eddd7994c 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -114,6 +114,32 @@ class WithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: + def algebra_generators(self): + r""" + Return generators for this algebra. + + This default implementation returns the basis of this algebra. + + OUTPUT: a family + + .. SEEALSO:: + + - :meth:`Modules.WithBasis.ParentMethods.basis` + - :meth:`MagmaticAlgebras.ParentMethods.algebra_generators` + + EXAMPLES:: + + sage: D4 = DescentAlgebra(QQ, 4).B() + sage: D4.algebra_generators() + Lazy family (...)_{i in Compositions of 4} + + sage: R. = ZZ[] + sage: P = PartitionAlgebra(1, x, R) + sage: P.algebra_generators() + Finite family {{{-1, 1}}: P[{{-1, 1}}], {{-1}, {1}}: P[{{-1}, {1}}]} + """ + return self.basis() + @abstract_method(optional = True) def product_on_basis(self, i, j): """ From 6a7b4f59ae87964d218bae3f75c757421eeb3f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Thu, 30 Apr 2015 13:56:39 +0200 Subject: [PATCH 608/665] 16659: fixed crosslinks --- src/sage/categories/magmatic_algebras.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index d0eddd7994c..48efdf0fd8c 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -81,8 +81,9 @@ def additional_structure(self): .. TODO:: - This category should be a :class:`CategoryWithAxiom`, the - axiom specifying the compability between the magma and + This category should be a + :class:`~sage.categories.category_with_axiom.CategoryWithAxiom`, + the axiom specifying the compability between the magma and module structure. EXAMPLES:: @@ -124,7 +125,7 @@ def algebra_generators(self): .. SEEALSO:: - - :meth:`Modules.WithBasis.ParentMethods.basis` + - :meth:`~sage.categories.modules_with_basis.ModulesWithBasis.ParentMethods.basis` - :meth:`MagmaticAlgebras.ParentMethods.algebra_generators` EXAMPLES:: From 30d332c24f20e212ad02bf6592690a6528e99bae Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Apr 2015 10:19:36 -0700 Subject: [PATCH 609/665] Marking tests as random. --- src/sage/combinat/tableau.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index ded6df4540d..a33db9c4614 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5185,11 +5185,10 @@ def random_element(self): EXAMPLES:: - sage: SemistandardTableaux(6).random_element() - [[2, 2], [3, 3], [6, 6]] - sage: SemistandardTableaux(6, max_entry=7).random_element() - [[2, 2], [3, 3], [6, 6]] - + sage: SemistandardTableaux(6).random_element() # random + [[1, 1, 2], [3, 5, 5]] + sage: SemistandardTableaux(6, max_entry=7).random_element() # random + [[2, 4, 4, 6, 6, 6]] """ from sage.rings.all import ZZ from sage.rings.arith import binomial From 02ba7045cf38725ca8cb5456df649b6bacdcbd8e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 30 Apr 2015 11:32:55 -0700 Subject: [PATCH 610/665] #18344: case issues in sage-fix-pkg-checksums --- src/bin/sage-fix-pkg-checksums | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bin/sage-fix-pkg-checksums b/src/bin/sage-fix-pkg-checksums index 65542b96145..aad18ae3c9e 100755 --- a/src/bin/sage-fix-pkg-checksums +++ b/src/bin/sage-fix-pkg-checksums @@ -12,12 +12,17 @@ for upstream in "$@" do tarball=`basename "$upstream"` pkg_name=${tarball%%-*} + # Convert to lowercase for the directory name: + pkg_name_lc=`echo $pkg_name | tr '[:upper:]' '[:lower:]'` pkg_compression=${tarball#*.tar} # gz or bz2 - if [ -d "$SAGE_ROOT/build/pkgs/$pkg_name" ]; then - sage_version=`cat "$SAGE_ROOT/build/pkgs/$pkg_name/package-version.txt" | sed 's/\.p[0-9][0-9]*$//'` + if [ -d "$SAGE_ROOT/build/pkgs/$pkg_name_lc" ]; then + sage_version=`cat "$SAGE_ROOT/build/pkgs/$pkg_name_lc/package-version.txt" | sed 's/\.p[0-9][0-9]*$//'` if [ ${tarball%.tar*} = "$pkg_name-$sage_version" ]; then echo >&2 $tarball - checksums="$SAGE_ROOT/build/pkgs/$pkg_name/checksums.ini" + if [ "$pkg_name" != "$pkg_name_lc" ]; then + echo >&2 " ** Note: case mismatch between upstream/$tarball and build/pkgs/$pkg_name_lc. **" + fi + checksums="$SAGE_ROOT/build/pkgs/$pkg_name_lc/checksums.ini" echo "tarball=$pkg_name-VERSION.tar$pkg_compression" > $checksums echo -n "sha1=" >> $checksums From 0f42daa7a40772ab4f7b08336311f9e8e617180e Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Thu, 30 Apr 2015 14:59:48 -0400 Subject: [PATCH 611/665] More documentation --- src/sage/plot/graphics.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 1384f7a4c87..4232b84b415 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -2084,8 +2084,7 @@ def ymax(self, ymax=None): def get_minmax_data(self): r""" - Return a dictionary whose keys give the xmin, xmax, ymin, and ymax - data for this graphic. + Return the x and y coordinate minimum and maximum .. warning:: @@ -2095,6 +2094,11 @@ def get_minmax_data(self): range of the axes, call methods :meth:`xmin`, :meth:`xmax`, :meth:`ymin`, :meth:`ymax`, or :meth:`set_axes_range`. + OUTPUT: + + A dictionary whose keys give the xmin, xmax, ymin, and ymax + data for this graphic. + EXAMPLES:: sage: g = line([(-1,1), (3,2)]) @@ -2152,6 +2156,19 @@ def _limit_output_aspect_ratio(self, xmin, xmax, ymin, ymax): """ Private helper function for :meth:`get_minmax_data` + INPUT: + + - ``xmin``, ``xmax``, ``ymin``, ``ymax`` -- bounding box for + the graphics. + + OUTPUT: + + A dictionary whose keys give the xmin, xmax, ymin, and ymax + data for this graphic. Possibly enlarged in order to keep the + width/height ratio (in output units, after factoring in the + chosen aspect ratio) of the plot is limited to `10^{-15}\dots + 10^{15}` to avoid floating point issues in matplotlib. + EXAMPLES:: sage: l = line([(0,0), (1,1)], aspect_ratio=1.0) From 66b28b1f0fe3bcbd743aecd4dc7f6c0bdf069b48 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Apr 2015 13:08:36 -0700 Subject: [PATCH 612/665] Changing indexing set of SchurAlgebra and implementation of TensorSpace. --- src/sage/algebras/catalog.py | 2 + src/sage/algebras/schur_algebra.py | 346 +++++++++++++---------------- 2 files changed, 162 insertions(+), 186 deletions(-) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 88a30534497..a3d438cd184 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -27,6 +27,7 @@ ` - :func:`algebras.Quaternion ` +- :class:`algebras.Schur ` - :class:`algebras.Shuffle ` - :class:`algebras.Steenrod ` @@ -46,6 +47,7 @@ lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra', 'NilCoxeter') lazy_import('sage.algebras.hall_algebra', 'HallAlgebra', 'Hall') lazy_import('sage.algebras.shuffle_algebra', 'ShuffleAlgebra', 'Shuffle') +lazy_import('sage.algebras.schur_algebra', 'SchurAlgebra', 'Schur') lazy_import('sage.algebras.commutative_dga', 'GradedCommutativeAlgebra', 'GradedCommutative') lazy_import('sage.combinat.posets.incidence_algebras', 'IncidenceAlgebra', 'Incidence') del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 1afb27ba71a..79ff0f19dda 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -3,10 +3,10 @@ This file implements: -- Schur algebras for `GL_n` over an arbitrary field, +- Schur algebras for `GL_n` over an arbitrary field. - The canonical action of the Schur algebra on a tensor power of the standard - representation, + representation. - Using the above to calculate the characters of irreducible `GL_n` modules. @@ -32,21 +32,19 @@ from sage.categories.all import AlgebrasWithBasis from sage.categories.rings import Rings -from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModule_Tensor +from sage.combinat.cartesian_product import CartesianProduct from sage.combinat.integer_list import IntegerListsLex from sage.combinat.partition import Partitions, Partition from sage.combinat.permutation import Permutations from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.combinat.tableau import SemistandardTableaux -from sage.combinat.words.word import Word -from sage.combinat.words.words import Words from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten -from sage.rings.integer import Integer -from sage.rings.rational_field import QQ +from sage.rings.all import ZZ, QQ from copy import copy @@ -62,7 +60,7 @@ def _schur_I_nr_representatives(n, r, element, index): index.append(copy(element)) return - if len(element) == 0: + if not element: for i in range(1, n + 1): element.append(i) _schur_I_nr_representatives(n, r, element, index) @@ -82,7 +80,7 @@ def schur_representative_indices(n, r): More specifically, the basis for `S_K(n,r)` consists of equivalence classes of pairs words of length ``r`` on the alphabet - `1\dots n`, where the equivalence relation is simultaneous + `1 \dots n`, where the equivalence relation is simultaneous permutation of the two words. We can therefore fix a representative for each equivalence class in which the entries of the first word weakly increase, and the entries of the second word @@ -92,11 +90,12 @@ def schur_representative_indices(n, r): EXAMPLES:: sage: from sage.algebras.schur_algebra import schur_representative_indices - sage: schur_representative_indices(2,2) - [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), - (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), - (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), - (word: 22, word: 22)] + sage: schur_representative_indices(2, 2) + [((1, 1), (1, 1)), ((1, 1), (1, 2)), + ((1, 1), (2, 2)), ((1, 2), (1, 1)), + ((1, 2), (1, 2)), ((1, 2), (2, 1)), + ((1, 2), (2, 2)), ((2, 2), (1, 1)), + ((2, 2), (1, 2)), ((2, 2), (2, 2))] """ basis = [] I_nr_repr = _schur_I_nr_representatives(n, r, [], []) @@ -109,7 +108,7 @@ def schur_representative_indices(n, r): if e[k] != e[j]: I2 = [] if j == 0: - I1 = _schur_I_nr_representatives(n, k - j, [], []) + I1 = _schur_I_nr_representatives(n, k, [], []) else: I2 = _schur_I_nr_representatives(n, k - j, [], []) I = [] @@ -122,7 +121,7 @@ def schur_representative_indices(n, r): I2 = [] k += 1 if j == 0: - I1 = _schur_I_nr_representatives(n, k - j, [], []) + I1 = _schur_I_nr_representatives(n, k, [], []) else: I2 = _schur_I_nr_representatives(n, k - j, [], []) I = [] @@ -134,12 +133,12 @@ def schur_representative_indices(n, r): k += 1 for v in I1: - basis.append((Word(e), Word(v))) + basis.append((tuple(e), tuple(v))) return basis -def schur_representative_from_index(index): +def schur_representative_from_index(i0, i1): """ Simultaneously reorder a pair of words to obtain the equivalent element of the distinguished basis of the Schur algebra. @@ -150,7 +149,7 @@ def schur_representative_from_index(index): INPUT: - - A pair of words from `Words (range(1,n+1),r)` + - A pair of words from ``Words(range(1,n+1), r)`` OUTPUT: @@ -159,54 +158,60 @@ def schur_representative_from_index(index): EXAMPLES:: sage: from sage.algebras.schur_algebra import schur_representative_from_index - sage: w1 = Word([2,1,2,2]) - sage: w2 = Word([1,3,0,0]) - sage: schur_representative_from_index((w1,w2)) - (word: 1222, word: 3001) + sage: schur_representative_from_index([2,1,2,2], [1,3,0,0]) + ((1, 2, 2, 2), (3, 0, 0, 1)) """ w = [] - for i in range(len(index[0])): - w.append((index[0][i], index[1][i])) + for i, val in enumerate(i0): + w.append((val, i1[i])) w.sort() - index = [[], []] - for i in range(len(w)): - index[0].append(w[i][0]) - index[1].append(w[i][1]) - return tuple(map(Word, index)) + i0 = [] + i1 = [] + for pair in w: + i0.append(pair[0]) + i1.append(pair[1]) + return (tuple(i0), tuple(i1)) class SchurAlgebra(CombinatorialFreeModule): """ - This is the class that implements Schur algebras. + A Schur algebra. EXAMPLES:: - sage: from sage.algebras.all import SchurAlgebra - sage: S = SchurAlgebra(2, 2, ZZ); S - Schur Algebra (2,2) over Integer Ring - - TESTS:: - - sage: SchurAlgebra(-2, 2, ZZ) - Traceback (most recent call last): - ... - ValueError: n must be a positive integer (n=-2) - sage: SchurAlgebra(2, -2, ZZ) - Traceback (most recent call last): - ... - ValueError: r must be a non-negative integer (r=-2) - sage: SchurAlgebra(2, 2, 'niet') - Traceback (most recent call last): - ... - ValueError: R must be a commutative Ring (R=niet) + sage: S = SchurAlgebra(ZZ, 2, 2); S + Schur algebra (2, 2) over Integer Ring """ - def __init__(self, n, r, R): - if not isinstance(n, (int, Integer)) or n <= 0: - raise ValueError("n must be a positive integer (n=%s)" % (n)) - if not isinstance(r, (int, Integer)) or r < 0: - raise ValueError("r must be a non-negative integer (r=%s)" % (r)) + def __init__(self, R, n, r): + """ + Initialize ``self``. + + TESTS:: + + sage: S = SchurAlgebra(ZZ, 2, 2) + sage: TestSuite(S).run() + + :: + + sage: SchurAlgebra(ZZ, -2, 2) + Traceback (most recent call last): + ... + ValueError: n (=-2) must be a positive integer + sage: SchurAlgebra(ZZ, 2, -2) + Traceback (most recent call last): + ... + ValueError: r (=-2) must be a non-negative integer + sage: SchurAlgebra('niet', 2, 2) + Traceback (most recent call last): + ... + ValueError: R (=niet) must be a commutative ring + """ + if n not in ZZ or n <= 0: + raise ValueError("n (={}) must be a positive integer".format(n)) + if r not in ZZ or r < 0: + raise ValueError("r (={}) must be a non-negative integer".format(r)) if not R in Rings.Commutative(): - raise ValueError("R must be a commutative Ring (R=%s)" % (R)) + raise ValueError("R (={}) must be a commutative ring".format(R)) self._n = n self._r = r @@ -221,12 +226,10 @@ def _repr_(self): EXAMPLES:: - sage: from sage.algebras.all import SchurAlgebra - sage: S = SchurAlgebra(4, 4, ZZ) # indirect doctest - sage: repr(S) - 'Schur Algebra (4,4) over Integer Ring' + sage: SchurAlgebra(ZZ, 4, 4) + Schur algebra (4, 4) over Integer Ring """ - msg = "Schur Algebra ({},{}) over {}" + msg = "Schur algebra ({}, {}) over {}" return msg.format(self._n, self._r, self.base_ring()) @cached_method @@ -236,8 +239,17 @@ def one(self): EXAMPLES:: - sage: from sage.algebras.all import SchurAlgebra - sage: S = SchurAlgebra(4, 4, ZZ) + sage: S = SchurAlgebra(ZZ, 2, 2) + sage: e = S.one(); e + B[((1, 1), (1, 1))] + B[((1, 2), (1, 2))] + B[((2, 2), (2, 2))] + + sage: x = S.an_element() + sage: x * e == x + True + sage: all(e * x == x for x in S.basis()) + True + + sage: S = SchurAlgebra(ZZ, 4, 4) sage: e = S.one() sage: x = S.an_element() sage: x * e == x @@ -245,7 +257,7 @@ def one(self): """ tt = IntegerListsLex(length=self._r, min_part=1, max_part=self._n, min_slope=0) - words = [Word(u) for u in tt] + words = [tuple(u) for u in tt] return self.sum(self._monomial((w, w)) for w in words) def product_on_basis(self, e_ij, e_kl): @@ -254,16 +266,15 @@ def product_on_basis(self, e_ij, e_kl): EXAMPLES:: - sage: from sage.algebras.all import SchurAlgebra - sage: S = SchurAlgebra(2, 3, QQ) + sage: S = SchurAlgebra(QQ, 2, 3) sage: B = S.basis() If we multiply two basis elements `x` and `y`, such that `x[1]` and `y[0]` are not permutations of each other, the result is zero :: - sage: x = B[(Word((1, 1, 1)), Word((1, 1, 2)))] - sage: y = B[(Word((1, 2, 2)),Word((1, 1, 2)))] + sage: x = B[((1, 1, 1), (1, 1, 2))] + sage: y = B[((1, 2, 2), (1, 1, 2))] sage: x * y 0 @@ -271,17 +282,17 @@ def product_on_basis(self, e_ij, e_kl): consists of the same tuple repeated twice (on either side), the result is either zero (if the previous case applies) or `x` :: - sage: ww = B[(Word((1, 2, 2)), Word((1, 2, 2)))] - sage: x = B[(Word((1, 2, 2)), Word((1, 1, 2)))] + sage: ww = B[((1, 2, 2), (1, 2, 2))] + sage: x = B[((1, 2, 2), (1, 1, 2))] sage: ww * x - B[(word: 122, word: 112)] + B[((1, 2, 2), (1, 1, 2))] An arbitrary product, on the other hand, may have multiplicities:: - sage: x = B[(Word((1, 1, 1)), Word((1, 1, 2)))] - sage: y = B[(Word((1, 1, 2)), Word((1, 2, 2)))] + sage: x = B[((1, 1, 1), (1, 1, 2))] + sage: y = B[((1, 1, 2), (1, 2, 2))] sage: x * y - 2*B[(word: 111, word: 122)] + 2*B[((1, 1, 1), (1, 2, 2))] """ j = e_ij[1] @@ -301,17 +312,17 @@ def product_on_basis(self, e_ij, e_kl): # Find s in I(n,r) such that (p,s) ~ (i,j) and (s,q) ~ (k,l) for e in e_pq: - Z_ijklpq = self.base_ring()(0) + Z_ijklpq = self.base_ring().zero() for s in Permutations([xx for xx in j]): - if (schur_representative_from_index((e[0], s)) == e_ij - and schur_representative_from_index((s, e[1])) == e_kl): + if (schur_representative_from_index(e[0], s) == e_ij + and schur_representative_from_index(s, e[1]) == e_kl): Z_ijklpq += self.base_ring().one() product += Z_ijklpq * b[e] return product -class TensorSpace(CombinatorialFreeModule): +class TensorSpace(CombinatorialFreeModule_Tensor): """ This is the ``r``-fold tensor product of an ``n``-dimensional free module over ``R``, equipped with an action of the Schur algebra @@ -320,16 +331,22 @@ class TensorSpace(CombinatorialFreeModule): EXAMPLES:: sage: from sage.algebras.all import TensorSpace - sage: TensorSpace(2, 3, QQ) + sage: TensorSpace(QQ, 2, 3) The 3-fold tensor product of a free module of dimension 2 over Rational Field """ - def __init__(self, n, r, R): - + def __init__(self, R, n, r): + """ + Initialize ``self``. + """ + C = CombinatorialFreeModule(R, range(1,n+1)) self._n = n self._r = r - self._R = R - CombinatorialFreeModule.__init__(self, R, Words(range(1, n + 1), r)) + self._sga = SymmetricGroupAlgebra(R, r) + self._schur = SchurAlgebra(R, n, r) + CombinatorialFreeModule_Tensor.__init__(self, [C]*r) + g = self._schur.module_morphism(self._monomial_product, codomain=self) + self._schur_action = self.module_morphism(g, codomain=self, position=1) def _repr_(self): """ @@ -338,7 +355,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.all import TensorSpace - sage: TensorSpace(2, 3, QQ) + sage: TensorSpace(QQ, 2, 3) The 3-fold tensor product of a free module of dimension 2 over Rational Field """ @@ -346,88 +363,38 @@ def _repr_(self): msg += " over {}" return msg.format(self._r, self._n, self.base_ring()) - def _basis_elt_from_permuted_word(self, v, perm): - """ - Return the basis element of ``self`` corresponding to applying - the permutation perm to a word v. - """ - return self.basis()[Word(v).apply_permutation_to_positions(perm)] - - def action_by_perm(self, t, perm): - """ - Apply a permutation to an element `t` of ``self`` - - INPUT: - - - ``perm`` -- an element of Permutations(self._r) - - ``t`` -- an element of ``self`` - - OUTPUT: - - - the output is the result of acting by ``perm`` on ``t`` - """ - h = self.module_morphism(self._basis_elt_from_permuted_word, - codomain=self) - return h(t, perm) - - def action_by_symmetric_group_algebra(self, t, z): - """ - Return the action by an element of the symmetric group algebra. - - INPUT: - - - ``t`` -- an element of ``self`` - - ``z`` -- an element of ``SymmetricGroupAlgebra(self._R,self._r)`` - - OUTPUT: - - result of action of ``z`` on ``t``. - """ - S = SymmetricGroupAlgebra(self._R, self._r) - assert z in S - sym_action = S.module_morphism(self.action_by_perm, codomain=self, - position=1) - return sym_action(t, z) - def _monomial_product(self, xi, v): """ Result of acting by the basis element ``xi`` of ``S`` on the basis element ``v`` of ``self``. """ x = self.zero() - for i in Words(range(1, self._n + 1), self._r): - if schur_representative_from_index((i, v)) == xi: - x += self.basis()[i] + for i in CartesianProduct(*[range(1,self._n+1)]*self._r): + if schur_representative_from_index(i, v) == xi: + x += self.basis()[tuple(i)] return x - def action_by_Schur_alg(self, nu, v): - r""" - Return the action of ``nu`` in Schur algebra on ``v`` in ``self``. - """ - A = SchurAlgebra(self._n, self._r, self._R) - assert nu in A - g = A.module_morphism(self._monomial_product, codomain=self) - action = self.module_morphism(g, codomain=self, position=1) - return action(nu, v) + class Element(CombinatorialFreeModule_Tensor.Element): + def _acted_upon_(self, elt, self_on_left=False): + """ + Return the action of ``elt`` on ``self``. + We add the *left* action of the Schur algebra, and the *right* + actions of the symmetric group algebra and the symemtric group. + """ + P = self.parent() + if self_on_left: + if elt in P._sga: + return P.sum_of_terms((tuple([m[i-1] for i in me]), c * ce) + for m,c in self for me,ce in elt) -def bracket(r, X, S): - r""" - Given ``X`` a set of permutations of ``r`` in cycle notation, - return the sum in the symmetric group algebra - of those permutations, times their sign. + if elt in P._sga._indices: + return P.sum_of_terms((tuple([m[i-1] for i in elt]), c) + for m,c in self) - This implements the notation `\{X\}` from just before (5.3a) of Green. - - EXAMPLES:: - - sage: P = PermutationGroupElement - sage: S2 = SymmetricGroupAlgebra(QQ,2) - sage: sage.algebras.schur_algebra.bracket(2,[P(()),P((1,2))], S2) - () - (1,2) - """ - SG = SymmetricGroup(r) - return sum([x.sign() * S.basis()[SG(x)] for x in X]) + elif elt in P._schur: # self_on_left is False + return P._schur_action(elt, self) + return super(TensorSpace.Element, self)._acted_upon_(elt, self_on_left) def GL_n_irred_character(n, mu, KK): @@ -437,9 +404,9 @@ def GL_n_irred_character(n, mu, KK): INPUT: - - ``n`` -- a positive integer. - - ``mu`` -- a partition of at most ``n`` parts. - - ``KK`` -- a field. + - ``n`` -- a positive integer + - ``mu`` -- a partition of at most ``n`` parts + - ``KK`` -- a field OUTPUT: @@ -448,9 +415,9 @@ def GL_n_irred_character(n, mu, KK): EXAMPLES: - Over `\QQ`, the irreducible character for ``mu`` is the Schur - function associated to ``mu``, plus garbage terms (Schur - functions associated to partitions with more than `n` parts) :: + Over `\QQ`, the irreducible character for `\mu` is the Schur + function associated to `\mu`, plus garbage terms (Schur + functions associated to partitions with more than `n` parts):: sage: from sage.algebras.schur_algebra import GL_n_irred_character sage: z = GL_n_irred_character(2, [2], QQ) @@ -468,9 +435,9 @@ def GL_n_irred_character(n, mu, KK): in general be smaller. In characteristic `p`, for a one-part partition `(r)`, where - `r= a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, + `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, after 5.5d] the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] - ( pbasis[p^2]),\dots,` which is consistent with the following :: + ( pbasis[p^2]), \dots,` which is consistent with the following :: sage: from sage.algebras.schur_algebra import GL_n_irred_character sage: GL_n_irred_character(2, [7], GF(3)) # long time @@ -478,32 +445,34 @@ def GL_n_irred_character(n, mu, KK): """ mbasis = SymmetricFunctions(QQ).m() r = sum(mu) - A = SchurAlgebra(n, r, KK) - M = TensorSpace(n, r, KK) - S = SymmetricGroupAlgebra(KK, r) + M = TensorSpace(KK, n, r) + A = M._schur + SGA = M._sga #make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word ST = from_shape_and_word(mu, range(1, r + 1), convention='English') #make ell the reading word of the highest weight tableau of shape mu - ell = [] - for i in range(len(mu)): - for j in range(mu[i]): - ell.append(i + 1) + ell = [i+1 for i,l in enumerate(mu) for dummy in range(l)] + + e = M.basis()[tuple(ell)] # the element e_l - e = M.basis()[Word(ell)] # the element e_l - BracC = bracket(r, ST.column_stabilizer(), S) - f = M.action_by_symmetric_group_algebra(e, BracC) + # This is the notation `\{X\}` from just before (5.3a) of [GreenPoly]_. + S = SGA._indices + BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, + remove_zeros=False) + f = e * BracC #M.action_by_symmetric_group_algebra(e, BracC) # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig # module V_\mu is given by taking this f, and multiplying by all # xi_{i,ell} with ell as above and i semistandard. carter_lusztig = [] - for i in [Word(flatten(T)) for T in SemistandardTableaux(mu, max_entry=n)]: - schur_rep = schur_representative_from_index((i, Word(ell))) - y = M.action_by_Schur_alg(A.basis()[schur_rep], e) + for T in SemistandardTableaux(mu, max_entry=n): + i = tuple(flatten(T)) + schur_rep = schur_representative_from_index(i, tuple(ell)) + y = A.basis()[schur_rep] * e #M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) #Therefore, we now have carter_lusztig as a list giving the basis @@ -526,22 +495,26 @@ def GL_n_irred_character(n, mu, KK): # of semistandard tableaux words with that content # graded_basis will consist of the a corresponding basis element - graded_basis = [] JJ = [] for i in range(len(contents)): graded_basis.append([]) JJ.append([]) - for i in [Word(flatten(T), range(1, n + 1)) - for T in SemistandardTableaux(mu, max_entry=n)]: - con = i.evaluation() - if all([con[j + 1] <= con[j] for j in range(len(con) - 1)]): - #don't test whether con is in Partitions, because con could - #have trailing zeros - JJ[contents.index(Partition(con))].append(i) - schur_rep = schur_representative_from_index((i, Word(ell))) - x = M.action_by_Schur_alg(A.basis()[schur_rep], f) - graded_basis[contents.index(Partition(con))].append(x.to_vector()) + for T in SemistandardTableaux(mu, max_entry=n): + i = tuple(flatten(T)) + # Get the content of T + con = [0]*n + for a in i: + con[a - 1] += 1 + try: + P = Partition(con) + P_index = contents.index(P) + JJ[P_index].append(i) + schur_rep = schur_representative_from_index(i, tuple(ell)) + x = A.basis()[schur_rep] * f #M.action_by_Schur_alg(A.basis()[schur_rep], f) + graded_basis[P_index].append(x.to_vector()) + except ValueError: + pass #There is an inner product on the Carter-Lusztig module V_\mu; its #maximal submodule is exactly the kernel of the inner product. @@ -566,3 +539,4 @@ def GL_n_irred_character(n, mu, KK): Angle = Matrix(Mat) Phi += (len(JJ[aa]) - Angle.nullity()) * mbasis(contents[aa]) return Phi + From 08861457389919f62fae8a1f2eaf0679e939e8f5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Apr 2015 18:26:03 -0700 Subject: [PATCH 613/665] Some futher cleanup and speedups. --- src/doc/en/reference/algebras/index.rst | 2 +- src/sage/algebras/all.py | 2 +- src/sage/algebras/schur_algebra.py | 232 +++++++++++++++++------- 3 files changed, 171 insertions(+), 65 deletions(-) diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 467b1be19f1..296a5f9b15d 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -31,13 +31,13 @@ Algebras sage/algebras/iwahori_hecke_algebra sage/algebras/nil_coxeter_algebra sage/algebras/affine_nil_temperley_lieb - sage/algebras/schur_algebra sage/algebras/hall_algebra sage/algebras/jordan_algebra sage/algebras/quatalg/quaternion_algebra + sage/algebras/schur_algebra sage/algebras/shuffle_algebra sage/algebras/steenrod/steenrod_algebra diff --git a/src/sage/algebras/all.py b/src/sage/algebras/all.py index c9d162f9ae7..9a5113cba67 100644 --- a/src/sage/algebras/all.py +++ b/src/sage/algebras/all.py @@ -41,7 +41,7 @@ from iwahori_hecke_algebra import IwahoriHeckeAlgebra from affine_nil_temperley_lieb import AffineNilTemperleyLiebTypeA lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra') -lazy_import('sage.algebras.schur_algebra', ['SchurAlgebra', 'TensorSpace']) +lazy_import('sage.algebras.schur_algebra', ['SchurAlgebra', 'SchurTensorModule']) lazy_import('sage.algebras.hall_algebra', 'HallAlgebra') diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 79ff0f19dda..8c1580c4d73 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -40,38 +40,46 @@ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.combinat.tableau import SemistandardTableaux +from sage.functions.other import binomial from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten from sage.rings.all import ZZ, QQ -from copy import copy +def _schur_I_nr_representatives(n, r): + r""" + Internal function called by :func:`schur_representation_indices`, + which generates all weakly increasing words of length ``r`` in the + alphabet ``1, 2, ..., n``. -def _schur_I_nr_representatives(n, r, element, index): - """ - Internal function called by :func:`schur_representation_indices`. + EXAMPLES:: + + sage: from sage.algebras.schur_algebra import _schur_I_nr_representatives + sage: _schur_I_nr_representatives(2, 4) + ((1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 2, 2), (1, 2, 2, 2), (2, 2, 2, 2)) """ if r == 0: - return index - - if len(element) == r: - index.append(copy(element)) - return + return () - if not element: - for i in range(1, n + 1): - element.append(i) - _schur_I_nr_representatives(n, r, element, index) - element.pop() - else: - for i in range(element[-1], n + 1): - element.append(i) - _schur_I_nr_representatives(n, r, element, index) + index = [] + element = [1] + while element: + if element[-1] > n: element.pop() + if element: + element[-1] += 1 + continue + + if len(element) == r: + index.append(tuple(element)) + element[-1] += 1 + continue + + element.append(element[-1]) - return index + return tuple(index) def schur_representative_indices(n, r): @@ -98,7 +106,7 @@ def schur_representative_indices(n, r): ((2, 2), (1, 2)), ((2, 2), (2, 2))] """ basis = [] - I_nr_repr = _schur_I_nr_representatives(n, r, [], []) + I_nr_repr = _schur_I_nr_representatives(n, r) for e in I_nr_repr: j = 0 k = 0 @@ -108,9 +116,9 @@ def schur_representative_indices(n, r): if e[k] != e[j]: I2 = [] if j == 0: - I1 = _schur_I_nr_representatives(n, k, [], []) + I1 = _schur_I_nr_representatives(n, k) else: - I2 = _schur_I_nr_representatives(n, k - j, [], []) + I2 = _schur_I_nr_representatives(n, k - j) I = [] for m1 in range(len(I1)): for m2 in range(len(I2)): @@ -121,9 +129,9 @@ def schur_representative_indices(n, r): I2 = [] k += 1 if j == 0: - I1 = _schur_I_nr_representatives(n, k, [], []) + I1 = _schur_I_nr_representatives(n, k) else: - I2 = _schur_I_nr_representatives(n, k - j, [], []) + I2 = _schur_I_nr_representatives(n, k - j) I = [] for m1 in range(len(I1)): for m2 in range(len(I2)): @@ -174,13 +182,34 @@ def schur_representative_from_index(i0, i1): class SchurAlgebra(CombinatorialFreeModule): - """ + r""" A Schur algebra. + Let `R` be a commutative ring, `n` be a positive integer, and `r` + be a non-negative integer. Define `A_R(n,r)` to be the set of + homogeneous polynomials of degree `r` in `n^2` variables `x_{ij}`. + Therefore we can write `R[x_{ij}] = \bigoplus_{r \geq 0} A_R(n,r)`, + and `R[x_{ij}]` is known to be a bialgebra with coproduct given by + `\Delta(x_{ij}) = \sum_l x_{il} \otimes x_{lj}` and counit + `\varepsilon(x_{ij}) = \delta_{ij}`. Therefore `A_R(n,r)` is a + subcoalgebra of `R[x_{ij}]`. The *Schur algebra* `S_R(n,r)` is the + linear dual to `A_R(n,r)`, that is `S_R(n,r) := \Hom(A_R(n,r), R)`, + and `S_R(n,r)` obtains its algebra structure naturally by dualizing + the comultiplication of `A_R(n,r)`. + + Let `V = R^n`. One of the most important properties of the Schur + algebra `S_R(n, r)` is that it is isomorphic to the endomorphisms + of `V^{\otimes r}` which commute with the natural action of `S_r`. + EXAMPLES:: sage: S = SchurAlgebra(ZZ, 2, 2); S Schur algebra (2, 2) over Integer Ring + + REFERENCES: + + - [GreenPoly]_ + - :wikipedia:`Schur_algebra` """ def __init__(self, R, n, r): """ @@ -235,7 +264,7 @@ def _repr_(self): @cached_method def one(self): """ - Return the one of the algebra. + Return the element `1` of ``self``. EXAMPLES:: @@ -271,16 +300,14 @@ def product_on_basis(self, e_ij, e_kl): If we multiply two basis elements `x` and `y`, such that `x[1]` and `y[0]` are not permutations of each other, the - result is zero :: + result is zero:: - sage: x = B[((1, 1, 1), (1, 1, 2))] - sage: y = B[((1, 2, 2), (1, 1, 2))] - sage: x * y + sage: S.product_on_basis(((1, 1, 1), (1, 1, 2)), ((1, 2, 2), (1, 1, 2))) 0 If we multiply a basis element `x` by a basis element which consists of the same tuple repeated twice (on either side), - the result is either zero (if the previous case applies) or `x` :: + the result is either zero (if the previous case applies) or `x`:: sage: ww = B[((1, 2, 2), (1, 2, 2))] sage: x = B[((1, 2, 2), (1, 1, 2))] @@ -321,30 +348,69 @@ def product_on_basis(self, e_ij, e_kl): return product + def dimension(self): + r""" + Return the dimension of ``self``. -class TensorSpace(CombinatorialFreeModule_Tensor): - """ - This is the ``r``-fold tensor product of an ``n``-dimensional free - module over ``R``, equipped with an action of the Schur algebra - `S(n,r)` and the symmetric group `S_r`. + The dimension of the Schur algebra `S_R(n, r)` is + + .. MATH:: + + \dim S_R(n,r) = \binom{n^2+r-1}{r}. + + EXAMPLES:: + + sage: S = SchurAlgebra(QQ, 4, 2) + sage: S.dimension() + 136 + sage: S = SchurAlgebra(QQ, 2, 4) + sage: S.dimension() + 35 + """ + return binomial(self._n**2 + self._r - 1, self._r) + + +class SchurTensorModule(CombinatorialFreeModule_Tensor): + r""" + The space `V^{\otimes r}` where `V = R^n` equipped with a left action + of the Schur algebra `S_R(n,r)` and a right action of the symmetric + group `S_r`. + + Let `R` be a commutative ring and `V = R^n`. We consider the module + `V^{\otimes r}` equppied with a natural right action of the symmetric + group `S_r` given by + + .. MATH:: + + (v_1 \otimes v_2 \otimes \cdots \otimes v_n) \sigma + = v_{\sigma(1)} \otimes v_{\simga(2)} \otimes \cdots + \otimes v_{\simga(n)}. + + The Schur algebra `S_R(n,r)` is naturally isomorphic to the + endomorphisms of `V^{\otimes r}` which commutes with the `S_r` action. + We let the natural left action of `S_R(n,r)` by this isomorphism. EXAMPLES:: - sage: from sage.algebras.all import TensorSpace - sage: TensorSpace(QQ, 2, 3) + sage: SchurTensorModule(QQ, 2, 3) The 3-fold tensor product of a free module of dimension 2 over Rational Field """ def __init__(self, R, n, r): """ Initialize ``self``. + + TESTS:: + + sage: T = SchurTensorModule(QQ, 2, 3) + sage: TestSuite(T).run() """ C = CombinatorialFreeModule(R, range(1,n+1)) self._n = n self._r = r self._sga = SymmetricGroupAlgebra(R, r) self._schur = SchurAlgebra(R, n, r) - CombinatorialFreeModule_Tensor.__init__(self, [C]*r) + CombinatorialFreeModule_Tensor.__init__(self, tuple([C]*r)) g = self._schur.module_morphism(self._monomial_product, codomain=self) self._schur_action = self.module_morphism(g, codomain=self, position=1) @@ -354,8 +420,7 @@ def _repr_(self): EXAMPLES:: - sage: from sage.algebras.all import TensorSpace - sage: TensorSpace(QQ, 2, 3) + sage: SchurTensorModule(QQ, 2, 3) The 3-fold tensor product of a free module of dimension 2 over Rational Field """ @@ -365,14 +430,22 @@ def _repr_(self): def _monomial_product(self, xi, v): """ - Result of acting by the basis element ``xi`` of ``S`` on the - basis element ``v`` of ``self``. + Result of acting by the basis element ``xi`` of the corresponding + Schur algebra on the basis element ``v`` of ``self``. + + EXAMPLES:: + + sage: T = SchurTensorModule(QQ, 2, 3) + sage: xi = T._schur.basis().keys()[4]; xi + ((1, 1, 2), (1, 1, 1)) + sage: T._monomial_product(xi, (1, 1, 1)) + B[1] # B[1] # B[2] + B[1] # B[2] # B[1] + B[2] # B[1] # B[1] """ - x = self.zero() + ret = [] for i in CartesianProduct(*[range(1,self._n+1)]*self._r): if schur_representative_from_index(i, v) == xi: - x += self.basis()[tuple(i)] - return x + ret.append(tuple(i)) + return self.sum_of_monomials(ret) class Element(CombinatorialFreeModule_Tensor.Element): def _acted_upon_(self, elt, self_on_left=False): @@ -381,6 +454,40 @@ def _acted_upon_(self, elt, self_on_left=False): We add the *left* action of the Schur algebra, and the *right* actions of the symmetric group algebra and the symemtric group. + + EXAMPLES:: + + sage: T = SchurTensorModule(QQ, 2, 4) + sage: x = T.an_element() + sage: A = SchurAlgebra(QQ, 2, 4) + sage: y = A.an_element() + sage: y * x + 14*B[1] # B[1] # B[1] # B[1] + sage: x * y + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for '*': ... + + :: + + sage: SGA = SymmetricGroupAlgebra(QQ, 4) + sage: y = SGA.an_element() + sage: x * y + 14*B[1] # B[1] # B[1] # B[1] + 17*B[1] # B[1] # B[1] # B[2] + + 7*B[1] # B[1] # B[2] # B[1] + 9*B[1] # B[2] # B[1] # B[1] + + 2*B[2] # B[1] # B[1] # B[1] + sage: y * x + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for '*': ... + + :: + + sage: S = Permutations(4) + sage: y = S.an_element() + sage: x * y + 2*B[1] # B[1] # B[1] # B[1] + 3*B[1] # B[1] # B[1] # B[2] + + 2*B[2] # B[1] # B[1] # B[1] """ P = self.parent() if self_on_left: @@ -394,10 +501,10 @@ def _acted_upon_(self, elt, self_on_left=False): elif elt in P._schur: # self_on_left is False return P._schur_action(elt, self) - return super(TensorSpace.Element, self)._acted_upon_(elt, self_on_left) + return super(SchurTensorModule.Element, self)._acted_upon_(elt, self_on_left) -def GL_n_irred_character(n, mu, KK): +def GL_irreducible_character(n, mu, KK): r""" Return the character of the irreducible module indexed by ``mu`` of `GL(n)` over the field ``KK``. @@ -419,16 +526,15 @@ def GL_n_irred_character(n, mu, KK): function associated to `\mu`, plus garbage terms (Schur functions associated to partitions with more than `n` parts):: - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: z = GL_n_irred_character(2, [2], QQ) + sage: from sage.algebras.schur_algebra import GL_irreducible_character + sage: z = GL_irreducible_character(2, [2], QQ) sage: sbasis = SymmetricFunctions(QQ).s() sage: sbasis(z) s[2] - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: z = GL_n_irred_character(4, [3, 2], QQ) # long time - sage: sbasis = SymmetricFunctions(QQ).s() # long time - sage: sbasis(z) # long time + sage: z = GL_irreducible_character(4, [3, 2], QQ) + sage: sbasis = SymmetricFunctions(QQ).s() + sage: sbasis(z) -5*s[1, 1, 1, 1, 1] + s[3, 2] Over a Galois field, the irreducible character for `\mu` will @@ -439,13 +545,13 @@ def GL_n_irred_character(n, mu, KK): after 5.5d] the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]), \dots,` which is consistent with the following :: - sage: from sage.algebras.schur_algebra import GL_n_irred_character - sage: GL_n_irred_character(2, [7], GF(3)) # long time + sage: from sage.algebras.schur_algebra import GL_irreducible_character + sage: GL_irreducible_character(2, [7], GF(3)) m[4, 3] + m[6, 1] + m[7] """ mbasis = SymmetricFunctions(QQ).m() r = sum(mu) - M = TensorSpace(KK, n, r) + M = SchurTensorModule(KK, n, r) A = M._schur SGA = M._sga @@ -528,15 +634,15 @@ def GL_n_irred_character(n, mu, KK): length = len(carter_lusztig) - Phi = mbasis.zero() + phi = mbasis.zero() for aa in range(len(contents)): - Mat = [] + mat = [] for kk in range(len(JJ[aa])): temp = [] for j in range(length): temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) - Mat.append(temp) - Angle = Matrix(Mat) - Phi += (len(JJ[aa]) - Angle.nullity()) * mbasis(contents[aa]) - return Phi + mat.append(temp) + angle = Matrix(mat) + phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa]) + return phi From c3356ebb98b93142a5a06720b66dfff14dd5f294 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 30 Apr 2015 19:15:35 -0700 Subject: [PATCH 614/665] Added some doctests. --- src/sage/modular/abvar/finite_subgroup.py | 48 +++++++++++++---------- src/sage/modular/abvar/torsion_point.py | 39 +++++++++++------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 03b5dad950b..161849b88bd 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -106,33 +106,41 @@ class FiniteSubgroup(Module): + r""" + A finite subgroup of a modular abelian variety. - Element = TorsionPoint + INPUT: - def __init__(self, abvar, field_of_definition=QQ): - """ - A finite subgroup of a modular abelian variety. + - ``abvar`` -- a modular abelian variety - INPUT: + - ``field_of_definition`` -- a field over which this group is defined - - ``abvar`` -- a modular abelian variety + EXAMPLES: - - ``field_of_definition`` -- a field over which this group is - defined + This is an abstract base class, so there are no instances of + this class itself:: - EXAMPLES: + sage: A = J0(37) + sage: G = A.torsion_subgroup(3); G + Finite subgroup with invariants [3, 3, 3, 3] over QQ of Abelian variety J0(37) of dimension 2 + sage: type(G) + + sage: from sage.modular.abvar.finite_subgroup import FiniteSubgroup + sage: isinstance(G, FiniteSubgroup) + True + """ + + Element = TorsionPoint + + def __init__(self, abvar, field_of_definition=QQ): + """ + Initialize ``self``. - This is an abstract base class, so there are no instances of - this class itself:: + TESTS:: - sage: A = J0(37) - sage: G = A.torsion_subgroup(3); G - Finite subgroup with invariants [3, 3, 3, 3] over QQ of Abelian variety J0(37) of dimension 2 - sage: type(G) - - sage: from sage.modular.abvar.finite_subgroup import FiniteSubgroup - sage: isinstance(G, FiniteSubgroup) - True + sage: A = J0(11) + sage: G = A.torsion_subgroup(2) + sage: TestSuite(G).run() # long time """ from sage.categories.category import Category from sage.categories.fields import Fields @@ -657,7 +665,7 @@ def _element_constructor_(self, x, check=True): def __contains__(self, x): """ - Returns True if `x` is contained in this finite subgroup. + Return ``True`` if ``x`` is contained in this finite subgroup. EXAMPLES: diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index d109bf7b930..9286260b4b0 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -23,29 +23,38 @@ from sage.structure.element import ModuleElement class TorsionPoint(ModuleElement): - def __init__(self, parent, element, check=True): - r""" - An element of a finite subgroup of a modular abelian variety. + r""" + An element of a finite subgroup of a modular abelian variety. - INPUT: + INPUT: - - ``parent`` -- a finite subgroup of a modular abelian variety + - ``parent`` -- a finite subgroup of a modular abelian variety - - ``element`` -- a `\QQ`-vector space element that represents - this element in terms of the ambient rational homology + - ``element`` -- a `\QQ`-vector space element that represents + this element in terms of the ambient rational homology - - ``check`` -- bool (default: True): whether to check that - element is in the appropriate vector space + - ``check`` -- bool (default: ``True``): whether to check that + element is in the appropriate vector space - EXAMPLES: + EXAMPLES: - The following calls the TorsionPoint constructor implicitly:: + The following calls the :class:`TorsionPoint` constructor implicitly:: + + sage: J = J0(11) + sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G + Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 + sage: type(G.0) + + """ + def __init__(self, parent, element, check=True): + """ + Initialize ``self``. + + EXAMPLES:: sage: J = J0(11) - sage: G = J.finite_subgroup([[1/3,0], [0,1/5]]); G - Finite subgroup with invariants [15] over QQbar of Abelian variety J0(11) of dimension 1 - sage: type(G.0) - + sage: G = J.finite_subgroup([[1/2,0], [0,1/2]]) + sage: TestSuite(G).run() # long time """ ModuleElement.__init__(self, parent) if check: From d0b30ccc97b1d3b8bca056d17b9f3730f4f0011e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 1 May 2015 10:14:25 +0200 Subject: [PATCH 615/665] trac #9123 review commit (pep8 and doc corrections) --- src/sage/algebras/schur_algebra.py | 68 +++++++++++++++--------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 8c1580c4d73..651cebf4da6 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -41,7 +41,6 @@ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.combinat.tableau import SemistandardTableaux from sage.functions.other import binomial -from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten @@ -51,7 +50,7 @@ def _schur_I_nr_representatives(n, r): r""" Internal function called by :func:`schur_representation_indices`, - which generates all weakly increasing words of length ``r`` in the + which generates all weakly increasing tuples of length ``r`` in the alphabet ``1, 2, ..., n``. EXAMPLES:: @@ -87,12 +86,12 @@ def schur_representative_indices(n, r): Return a set which functions as a basis of `S_K(n,r)`. More specifically, the basis for `S_K(n,r)` consists of - equivalence classes of pairs words of length ``r`` on the alphabet - `1 \dots n`, where the equivalence relation is simultaneous - permutation of the two words. We can therefore fix a + equivalence classes of pairs of tuples of length ``r`` on the alphabet + `\{1, \dots, n\}`, where the equivalence relation is simultaneous + permutation of the two tuples. We can therefore fix a representative for each equivalence class in which the entries of - the first word weakly increase, and the entries of the second word - whose corresponding values in the first word are equal, also + the first tuple weakly increase, and the entries of the second tuple + whose corresponding values in the first tuple are equal, also weakly increase. EXAMPLES:: @@ -148,7 +147,7 @@ def schur_representative_indices(n, r): def schur_representative_from_index(i0, i1): """ - Simultaneously reorder a pair of words to obtain the equivalent + Simultaneously reorder a pair of tuples to obtain the equivalent element of the distinguished basis of the Schur algebra. .. SEEALSO:: @@ -157,11 +156,11 @@ def schur_representative_from_index(i0, i1): INPUT: - - A pair of words from ``Words(range(1,n+1), r)`` + - A pair of tuples of length `r` with elements in `\{1,\dots,n\}` OUTPUT: - - The corresponding pair of words ordered correctly. + - The corresponding pair of tuples ordered correctly. EXAMPLES:: @@ -193,7 +192,7 @@ class SchurAlgebra(CombinatorialFreeModule): `\Delta(x_{ij}) = \sum_l x_{il} \otimes x_{lj}` and counit `\varepsilon(x_{ij}) = \delta_{ij}`. Therefore `A_R(n,r)` is a subcoalgebra of `R[x_{ij}]`. The *Schur algebra* `S_R(n,r)` is the - linear dual to `A_R(n,r)`, that is `S_R(n,r) := \Hom(A_R(n,r), R)`, + linear dual to `A_R(n,r)`, that is `S_R(n,r) := \hom(A_R(n,r), R)`, and `S_R(n,r)` obtains its algebra structure naturally by dualizing the comultiplication of `A_R(n,r)`. @@ -367,7 +366,7 @@ def dimension(self): sage: S.dimension() 35 """ - return binomial(self._n**2 + self._r - 1, self._r) + return binomial(self._n ** 2 + self._r - 1, self._r) class SchurTensorModule(CombinatorialFreeModule_Tensor): @@ -377,18 +376,18 @@ class SchurTensorModule(CombinatorialFreeModule_Tensor): group `S_r`. Let `R` be a commutative ring and `V = R^n`. We consider the module - `V^{\otimes r}` equppied with a natural right action of the symmetric + `V^{\otimes r}` equipped with a natural right action of the symmetric group `S_r` given by .. MATH:: (v_1 \otimes v_2 \otimes \cdots \otimes v_n) \sigma - = v_{\sigma(1)} \otimes v_{\simga(2)} \otimes \cdots - \otimes v_{\simga(n)}. + = v_{\sigma(1)} \otimes v_{\sigma(2)} \otimes \cdots + \otimes v_{\sigma(n)}. The Schur algebra `S_R(n,r)` is naturally isomorphic to the endomorphisms of `V^{\otimes r}` which commutes with the `S_r` action. - We let the natural left action of `S_R(n,r)` by this isomorphism. + We get the natural left action of `S_R(n,r)` by this isomorphism. EXAMPLES:: @@ -405,12 +404,12 @@ def __init__(self, R, n, r): sage: T = SchurTensorModule(QQ, 2, 3) sage: TestSuite(T).run() """ - C = CombinatorialFreeModule(R, range(1,n+1)) + C = CombinatorialFreeModule(R, range(1, n + 1)) self._n = n self._r = r self._sga = SymmetricGroupAlgebra(R, r) self._schur = SchurAlgebra(R, n, r) - CombinatorialFreeModule_Tensor.__init__(self, tuple([C]*r)) + CombinatorialFreeModule_Tensor.__init__(self, tuple([C] * r)) g = self._schur.module_morphism(self._monomial_product, codomain=self) self._schur_action = self.module_morphism(g, codomain=self, position=1) @@ -442,7 +441,7 @@ def _monomial_product(self, xi, v): B[1] # B[1] # B[2] + B[1] # B[2] # B[1] + B[2] # B[1] # B[1] """ ret = [] - for i in CartesianProduct(*[range(1,self._n+1)]*self._r): + for i in CartesianProduct(*[range(1, self._n + 1)] * self._r): if schur_representative_from_index(i, v) == xi: ret.append(tuple(i)) return self.sum_of_monomials(ret) @@ -453,7 +452,7 @@ def _acted_upon_(self, elt, self_on_left=False): Return the action of ``elt`` on ``self``. We add the *left* action of the Schur algebra, and the *right* - actions of the symmetric group algebra and the symemtric group. + actions of the symmetric group algebra and the symmetric group. EXAMPLES:: @@ -492,14 +491,15 @@ def _acted_upon_(self, elt, self_on_left=False): P = self.parent() if self_on_left: if elt in P._sga: - return P.sum_of_terms((tuple([m[i-1] for i in me]), c * ce) - for m,c in self for me,ce in elt) + return P.sum_of_terms((tuple([m[i - 1] for i in me]), + c * ce) + for m, c in self for me, ce in elt) if elt in P._sga._indices: - return P.sum_of_terms((tuple([m[i-1] for i in elt]), c) - for m,c in self) + return P.sum_of_terms((tuple([m[i - 1] for i in elt]), c) + for m, c in self) - elif elt in P._schur: # self_on_left is False + elif elt in P._schur: # self_on_left is False return P._schur_action(elt, self) return super(SchurTensorModule.Element, self)._acted_upon_(elt, self_on_left) @@ -527,13 +527,12 @@ def GL_irreducible_character(n, mu, KK): functions associated to partitions with more than `n` parts):: sage: from sage.algebras.schur_algebra import GL_irreducible_character - sage: z = GL_irreducible_character(2, [2], QQ) sage: sbasis = SymmetricFunctions(QQ).s() + sage: z = GL_irreducible_character(2, [2], QQ) sage: sbasis(z) s[2] sage: z = GL_irreducible_character(4, [3, 2], QQ) - sage: sbasis = SymmetricFunctions(QQ).s() sage: sbasis(z) -5*s[1, 1, 1, 1, 1] + s[3, 2] @@ -541,8 +540,8 @@ def GL_irreducible_character(n, mu, KK): in general be smaller. In characteristic `p`, for a one-part partition `(r)`, where - `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, - after 5.5d] the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] + `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is (see [GreenPoly]_, + after 5.5d) the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]), \dots,` which is consistent with the following :: sage: from sage.algebras.schur_algebra import GL_irreducible_character @@ -560,7 +559,7 @@ def GL_irreducible_character(n, mu, KK): ST = from_shape_and_word(mu, range(1, r + 1), convention='English') #make ell the reading word of the highest weight tableau of shape mu - ell = [i+1 for i,l in enumerate(mu) for dummy in range(l)] + ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)] e = M.basis()[tuple(ell)] # the element e_l @@ -568,7 +567,7 @@ def GL_irreducible_character(n, mu, KK): S = SGA._indices BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, remove_zeros=False) - f = e * BracC #M.action_by_symmetric_group_algebra(e, BracC) + f = e * BracC # M.action_by_symmetric_group_algebra(e, BracC) # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig # module V_\mu is given by taking this f, and multiplying by all @@ -578,7 +577,7 @@ def GL_irreducible_character(n, mu, KK): for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) schur_rep = schur_representative_from_index(i, tuple(ell)) - y = A.basis()[schur_rep] * e #M.action_by_Schur_alg(A.basis()[schur_rep], e) + y = A.basis()[schur_rep] * e # M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) #Therefore, we now have carter_lusztig as a list giving the basis @@ -609,7 +608,7 @@ def GL_irreducible_character(n, mu, KK): for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) # Get the content of T - con = [0]*n + con = [0] * n for a in i: con[a - 1] += 1 try: @@ -617,7 +616,7 @@ def GL_irreducible_character(n, mu, KK): P_index = contents.index(P) JJ[P_index].append(i) schur_rep = schur_representative_from_index(i, tuple(ell)) - x = A.basis()[schur_rep] * f #M.action_by_Schur_alg(A.basis()[schur_rep], f) + x = A.basis()[schur_rep] * f # M.action_by_Schur_alg(A.basis()[schur_rep], f) graded_basis[P_index].append(x.to_vector()) except ValueError: pass @@ -645,4 +644,3 @@ def GL_irreducible_character(n, mu, KK): angle = Matrix(mat) phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa]) return phi - From 9e60492f145e2f1a80fbe9df41b48330ab01e510 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 30 Apr 2015 18:31:24 +0200 Subject: [PATCH 616/665] trac #18346: Make graph_backends.py into a .pyx --- src/module_list.py | 3 +++ src/sage/graphs/base/graph_backends.pxd | 4 ++++ .../base/{graph_backends.py => graph_backends.pyx} | 11 +++-------- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 src/sage/graphs/base/graph_backends.pxd rename src/sage/graphs/base/{graph_backends.py => graph_backends.pyx} (99%) diff --git a/src/module_list.py b/src/module_list.py index 85fd69746aa..84775ea3fda 100755 --- a/src/module_list.py +++ b/src/module_list.py @@ -390,6 +390,9 @@ def uname_specific(name, value, alternative): sources = ['sage/graphs/distances_all_pairs.pyx'], libraries = ['gmp']), + Extension('sage.graphs.base.graph_backends', + sources = ['sage/graphs/base/graph_backends.pyx']), + Extension('sage.graphs.base.static_dense_graph', sources = ['sage/graphs/base/static_dense_graph.pyx'], libraries = ['gmp']), diff --git a/src/sage/graphs/base/graph_backends.pxd b/src/sage/graphs/base/graph_backends.pxd new file mode 100644 index 00000000000..063e70e575e --- /dev/null +++ b/src/sage/graphs/base/graph_backends.pxd @@ -0,0 +1,4 @@ +from sage.structure.sage_object cimport SageObject + +cdef class GenericGraphBackend(SageObject): + pass diff --git a/src/sage/graphs/base/graph_backends.py b/src/sage/graphs/base/graph_backends.pyx similarity index 99% rename from src/sage/graphs/base/graph_backends.py rename to src/sage/graphs/base/graph_backends.pyx index e186b925c2d..917dc24e246 100644 --- a/src/sage/graphs/base/graph_backends.py +++ b/src/sage/graphs/base/graph_backends.pyx @@ -10,9 +10,7 @@ # http://www.gnu.org/licenses/ #******************************************************************************* -from sage.structure.sage_object import SageObject - -class GenericGraphBackend(SageObject): +cdef class GenericGraphBackend(SageObject): """ A generic wrapper for the backend of a graph. Various graph classes use extensions of this class. Note, this graph has a number of placeholder @@ -601,7 +599,6 @@ def __init__(self): sage: from sage.graphs.base.graph_backends import NetworkXGraphDeprecated sage: NetworkXGraphDeprecated() - doctest:... """ from sage.misc.superseded import deprecation @@ -622,7 +619,6 @@ def mutate(self): sage: from sage.graphs.base.graph_backends import NetworkXGraphDeprecated as NXGD sage: X = NXGD() - doctest:... sage: X.adj = {1:{2:7}, 2:{1:7}, 3:{2:[4,5,6,7]}, 2:{3:[4,5,6,7]}} sage: X.multiedges = True sage: G = X.mutate() @@ -691,7 +687,6 @@ def mutate(self): sage: from sage.graphs.base.graph_backends import NetworkXDiGraphDeprecated as NXDGD sage: X = NXDGD() - doctest:... sage: X.adj = {1:{2:7}, 2:{1:[7,8], 3:[4,5,6,7]}} sage: X.multiedges = True sage: G = X.mutate() @@ -748,7 +743,7 @@ def __init__(self, N=None): sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) - + """ if N is None: import networkx @@ -1137,7 +1132,7 @@ def iterator_edges(self, vertices, labels): sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) - + """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() From da8479ef8de84ce4d80b825138032da19c18f72b Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 30 Apr 2015 17:17:33 +0200 Subject: [PATCH 617/665] trac #18346: Move and indent three functions (nothing else is changed) --- src/sage/graphs/base/c_graph.pyx | 188 +++++++++++++++---------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index c9447e1fb36..c9d238eb73b 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1115,100 +1115,6 @@ cdef class CGraph: """ return self.num_arcs -cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels, - CGraph G) except ? -2: - """ - Returns an int representing the arbitrary hashable vertex u (whether or not - u is actually in the graph), or -1 if a new association must be made for u - to be a vertex. - - TESTS: - - We check that the bug described in :trac:`8406` is gone:: - - sage: G = Graph() - sage: R. = GF(3**3) - sage: S. = R[] - sage: G.add_vertex(a**2) - sage: G.add_vertex(x) - sage: G.vertices() - [a^2, x] - - And that the bug described in :trac:`9610` is gone:: - - sage: n = 20 - sage: k = 3 - sage: g = DiGraph() - sage: g.add_edges( (i,Mod(i+j,n)) for i in range(n) for j in range(1,k+1) ) - sage: g.vertices() - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] - sage: g.strongly_connected_components() - [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]] - - The bug in :trac:`14967` and :trac:`14853` is fixed:: - - sage: DiGraph({0: {}, 1/2: {}}) - Multi-digraph on 2 vertices - sage: A = Set([RDF.random_element(min=0, max=10) for k in range(10)]) - sage: G = Graph() - sage: G.add_vertices(A) - sage: Set(G.vertices()) == A - True - - """ - cdef int u_int - if u in vertex_ints: - return vertex_ints[u] - try: - u_int = u - except Exception: - return -1 - if u_int < 0 or u_int >= G.active_vertices.size or u_int in vertex_labels or u_int != u: - return -1 - return u_int - -cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels, - CGraph G): - """ - Returns the object represented by u_int, or None if this does not represent - a vertex. - """ - if u_int in vertex_labels: - return vertex_labels[u_int] - elif bitset_in(G.active_vertices, u_int): - return u_int - else: - return None - -cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels, - CGraph G, CGraph G_rev, bint reverse) except ? -1: - """ - Returns an int representing the arbitrary hashable vertex u, and updates, - if necessary, the translation dict and list. Adds a vertex if the label - is new. - """ - cdef int u_int = get_vertex(u, vertex_ints, vertex_labels, G) - if u_int != -1: - if not bitset_in(G.active_vertices, u_int): - bitset_add(G.active_vertices, u_int) - G.num_verts += 1 - if reverse: - bitset_add(G_rev.active_vertices, u_int) - G_rev.num_verts += 1 - return u_int - u_int = bitset_first_in_complement(G.active_vertices) - if u_int == -1: - G.realloc(2*G.active_vertices.size) - if reverse: - G_rev.realloc(2*G_rev.active_vertices.size) - return check_vertex(u, vertex_ints, vertex_labels, G, G_rev, reverse) - vertex_labels[u_int] = u - vertex_ints[u] = u_int - G.add_vertex(u_int) - if reverse: - G_rev.add_vertex(u_int) - return u_int - class CGraphBackend(GenericGraphBackend): """ Base class for sparse and dense graph backends. @@ -1252,6 +1158,100 @@ class CGraphBackend(GenericGraphBackend): _cg_rev = None _directed = None + cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels, + CGraph G) except ? -2: + """ + Returns an int representing the arbitrary hashable vertex u (whether or not + u is actually in the graph), or -1 if a new association must be made for u + to be a vertex. + + TESTS: + + We check that the bug described in :trac:`8406` is gone:: + + sage: G = Graph() + sage: R. = GF(3**3) + sage: S. = R[] + sage: G.add_vertex(a**2) + sage: G.add_vertex(x) + sage: G.vertices() + [a^2, x] + + And that the bug described in :trac:`9610` is gone:: + + sage: n = 20 + sage: k = 3 + sage: g = DiGraph() + sage: g.add_edges( (i,Mod(i+j,n)) for i in range(n) for j in range(1,k+1) ) + sage: g.vertices() + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + sage: g.strongly_connected_components() + [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]] + + The bug in :trac:`14967` and :trac:`14853` is fixed:: + + sage: DiGraph({0: {}, 1/2: {}}) + Multi-digraph on 2 vertices + sage: A = Set([RDF.random_element(min=0, max=10) for k in range(10)]) + sage: G = Graph() + sage: G.add_vertices(A) + sage: Set(G.vertices()) == A + True + + """ + cdef int u_int + if u in vertex_ints: + return vertex_ints[u] + try: + u_int = u + except Exception: + return -1 + if u_int < 0 or u_int >= G.active_vertices.size or u_int in vertex_labels or u_int != u: + return -1 + return u_int + + cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels, + CGraph G): + """ + Returns the object represented by u_int, or None if this does not represent + a vertex. + """ + if u_int in vertex_labels: + return vertex_labels[u_int] + elif bitset_in(G.active_vertices, u_int): + return u_int + else: + return None + + cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels, + CGraph G, CGraph G_rev, bint reverse) except ? -1: + """ + Returns an int representing the arbitrary hashable vertex u, and updates, + if necessary, the translation dict and list. Adds a vertex if the label + is new. + """ + cdef int u_int = get_vertex(u, vertex_ints, vertex_labels, G) + if u_int != -1: + if not bitset_in(G.active_vertices, u_int): + bitset_add(G.active_vertices, u_int) + G.num_verts += 1 + if reverse: + bitset_add(G_rev.active_vertices, u_int) + G_rev.num_verts += 1 + return u_int + u_int = bitset_first_in_complement(G.active_vertices) + if u_int == -1: + G.realloc(2*G.active_vertices.size) + if reverse: + G_rev.realloc(2*G_rev.active_vertices.size) + return check_vertex(u, vertex_ints, vertex_labels, G, G_rev, reverse) + vertex_labels[u_int] = u + vertex_ints[u] = u_int + G.add_vertex(u_int) + if reverse: + G_rev.add_vertex(u_int) + return u_int + def has_vertex(self, v): """ Returns whether ``v`` is a vertex of ``self``. From 5b765e1c0888b0661b2ae01de352d013c073efb3 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Thu, 30 Apr 2015 18:27:48 +0200 Subject: [PATCH 618/665] trac #18346: Rename calls to [get_vertex, vertex_label, check_vertex] into self.method calls --- src/sage/graphs/base/c_graph.pyx | 154 ++++++------------ src/sage/graphs/base/dense_graph.pyx | 54 +++--- src/sage/graphs/base/sparse_graph.pxd | 1 + src/sage/graphs/base/sparse_graph.pyx | 101 +++++------- .../graphs/base/static_sparse_backend.pxd | 2 +- .../graphs/base/static_sparse_backend.pyx | 2 +- src/sage/graphs/base/static_sparse_graph.pyx | 1 + src/sage/graphs/distances_all_pairs.pyx | 16 +- 8 files changed, 123 insertions(+), 208 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index c9d238eb73b..706b7877aec 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1158,8 +1158,7 @@ class CGraphBackend(GenericGraphBackend): _cg_rev = None _directed = None - cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels, - CGraph G) except ? -2: + cdef int get_vertex(self, object u) except ? -2: """ Returns an int representing the arbitrary hashable vertex u (whether or not u is actually in the graph), or -1 if a new association must be made for u @@ -1199,6 +1198,9 @@ class CGraphBackend(GenericGraphBackend): True """ + cdef dict vertex_ints = self.vertex_ints + cdef dict vertex_labels = self.vertex_labels + cdef CGraph G = self._cg cdef int u_int if u in vertex_ints: return vertex_ints[u] @@ -1210,12 +1212,15 @@ class CGraphBackend(GenericGraphBackend): return -1 return u_int - cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels, - CGraph G): + cdef object vertex_label(self, int u_int): """ Returns the object represented by u_int, or None if this does not represent a vertex. """ + cdef dict vertex_ints = self.vertex_ints + cdef dict vertex_labels = self.vertex_labels, + cdef CGraph G = self._cg + if u_int in vertex_labels: return vertex_labels[u_int] elif bitset_in(G.active_vertices, u_int): @@ -1223,14 +1228,18 @@ class CGraphBackend(GenericGraphBackend): else: return None - cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels, - CGraph G, CGraph G_rev, bint reverse) except ? -1: + cdef int check_labelled_vertex(self, object u, bint reverse) except ? -1: """ Returns an int representing the arbitrary hashable vertex u, and updates, if necessary, the translation dict and list. Adds a vertex if the label is new. """ - cdef int u_int = get_vertex(u, vertex_ints, vertex_labels, G) + cdef dict vertex_ints = self.vertex_ints + cdef dict vertex_labels = self.vertex_labels, + cdef CGraph G = self._cg + cdef CGraph G_rev = self._cg_rev + + cdef int u_int = self.get_vertex(u) if u_int != -1: if not bitset_in(G.active_vertices, u_int): bitset_add(G.active_vertices, u_int) @@ -1244,7 +1253,7 @@ class CGraphBackend(GenericGraphBackend): G.realloc(2*G.active_vertices.size) if reverse: G_rev.realloc(2*G_rev.active_vertices.size) - return check_vertex(u, vertex_ints, vertex_labels, G, G_rev, reverse) + return self.check_labelled_vertex(u, reverse) vertex_labels[u_int] = u vertex_ints[u] = u_int G.add_vertex(u_int) @@ -1273,10 +1282,7 @@ class CGraphBackend(GenericGraphBackend): sage: B.has_vertex(7) False """ - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) if v_int == -1: return False if not bitset_in((self._cg).active_vertices, v_int): @@ -1414,10 +1420,7 @@ class CGraphBackend(GenericGraphBackend): sage: h.degree() [1, 1] """ - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) if directed: return self._cg._in_degree(v_int) + self._cg._out_degree(v_int) d = 0 @@ -1443,10 +1446,7 @@ class CGraphBackend(GenericGraphBackend): sage: D.out_degree(1) 2 """ - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) if self._directed: return self._cg._out_degree(v_int) d = 0 @@ -1476,10 +1476,7 @@ class CGraphBackend(GenericGraphBackend): if not self._directed: return self.out_degree(v) - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) return self._cg_rev._out_degree(v_int) @@ -1532,11 +1529,7 @@ class CGraphBackend(GenericGraphBackend): name += 1 retval = name - check_vertex(name, - self.vertex_ints, - self.vertex_labels, - self._cg, - self._cg_rev, + self.check_labelled_vertex(name, (self._directed and self._cg_rev is not None)) # this will add the vertex @@ -1632,10 +1625,7 @@ class CGraphBackend(GenericGraphBackend): """ if not self.has_vertex(v): return - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) # delete each arc incident with v and v self._cg.del_vertex(v_int) @@ -1749,19 +1739,16 @@ class CGraphBackend(GenericGraphBackend): [1, 4, 5] """ cdef int u_int - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) # Sparse if self._cg_rev is not None: for u_int in self._cg_rev.out_neighbors(v_int): - yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + yield self.vertex_label(u_int) # Dense else: for u_int in self._cg.in_neighbors(v_int): - yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + yield self.vertex_label(u_int) def iterator_out_nbrs(self, v): """ @@ -1790,13 +1777,10 @@ class CGraphBackend(GenericGraphBackend): [1, 4, 5] """ cdef u_int - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) for u_int in self._cg.out_neighbors(v_int): - yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + yield self.vertex_label(u_int) def iterator_verts(self, verts=None): """ @@ -2056,7 +2040,7 @@ class CGraphBackend(GenericGraphBackend): cdef dict new_vx_ints = {} cdef dict new_vx_labels = {} for v in self.iterator_verts(None): - i = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg) + i = self.get_vertex(v) new_vx_ints[perm[v]] = i new_vx_labels[i] = perm[v] self.vertex_ints = new_vx_ints @@ -2097,14 +2081,8 @@ class CGraphBackend(GenericGraphBackend): # considering the out_neighbors on x's side, and in_neighbors on # y's side. - cdef int x_int = get_vertex(x, - self.vertex_ints, - self.vertex_labels, - self._cg) - cdef int y_int = get_vertex(y, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int x_int = self.get_vertex(x) + cdef int y_int = self.get_vertex(y) cdef int u = 0 cdef int v = 0 cdef int w = 0 @@ -2169,11 +2147,7 @@ class CGraphBackend(GenericGraphBackend): w = v while w != x_int: - shortest_path.append( - vertex_label(w, - self.vertex_ints, - self.vertex_labels, - self._cg)) + shortest_path.append(self.vertex_label(w)) w = pred_x[w] shortest_path.append(x) @@ -2184,11 +2158,7 @@ class CGraphBackend(GenericGraphBackend): w = pred_y[v] while w != y_int: - shortest_path.append( - vertex_label(w, - self.vertex_ints, - self.vertex_labels, - self._cg)) + shortest_path.append(self.vertex_label(w)) w = pred_y[w] shortest_path.append(y) @@ -2251,14 +2221,8 @@ class CGraphBackend(GenericGraphBackend): # define dictionaries like pred_current and pred_other, which # represent alternatively pred_x or pred_y according to the side # studied. - cdef int x_int = get_vertex(x, - self.vertex_ints, - self.vertex_labels, - self._cg) - cdef int y_int = get_vertex(y, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int x_int = self.get_vertex(x) + cdef int y_int = self.get_vertex(y) cdef int u = 0 cdef int v = 0 cdef int w = 0 @@ -2330,8 +2294,8 @@ class CGraphBackend(GenericGraphBackend): # If the neighbor is new, adds its non-found neighbors to # the queue. if w not in dist_current: - v_obj = vertex_label(v, self.vertex_ints, self.vertex_labels, self._cg) - w_obj = vertex_label(w, self.vertex_ints, self.vertex_labels, self._cg) + v_obj = self.vertex_label(v) + w_obj = self.vertex_label(w) edge_label = self.get_edge_label(v_obj, w_obj) if side == 1 else self.get_edge_label(w_obj, v_obj) heappush(queue, (distance + edge_label, side, v, w)) @@ -2343,11 +2307,7 @@ class CGraphBackend(GenericGraphBackend): w = meeting_vertex while w != x_int: - shortest_path.append( - vertex_label(w, - self.vertex_ints, - self.vertex_labels, - self._cg)) + shortest_path.append(self.vertex_label(w)) w = pred_x[w] shortest_path.append(x) @@ -2358,11 +2318,7 @@ class CGraphBackend(GenericGraphBackend): w = pred_y[meeting_vertex] while w != y_int: - shortest_path.append( - vertex_label(w, - self.vertex_ints, - self.vertex_labels, - self._cg)) + shortest_path.append(self.vertex_label(w)) w = pred_y[w] shortest_path.append(y) @@ -2419,7 +2375,7 @@ class CGraphBackend(GenericGraphBackend): distances = {} d = 0 - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg) + v_int = self.get_vertex(v) bitset_init(seen, (self._cg).active_vertices.size) bitset_set_first_n(seen, 0) @@ -2439,7 +2395,7 @@ class CGraphBackend(GenericGraphBackend): if bitset_not_in(seen, v_int): bitset_add(seen, v_int) - distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = distances[vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)] + [vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] + distances[self.vertex_label(v_int)] = distances[self.vertex_label(u_int)] + [self.vertex_label(v_int)] next_layer.extend([(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)]) current_layer = next_layer @@ -2653,7 +2609,7 @@ class CGraphBackend(GenericGraphBackend): if v_int == -1: return True - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, cg) + v = self.vertex_label(v_int) return len(list(self.depth_first_search(v, ignore_direction=True))) == cg.num_verts def is_strongly_connected(self): @@ -2682,7 +2638,7 @@ class CGraphBackend(GenericGraphBackend): if v_int == -1: return True - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) return (self._cg).num_verts == len(list(self.depth_first_search(v))) and \ (self._cg).num_verts == len(list(self.depth_first_search(v, reverse=True))) @@ -2711,10 +2667,7 @@ class CGraphBackend(GenericGraphBackend): sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v in g]) True """ - cdef int v_int = get_vertex(v, - self.vertex_ints, - self.vertex_labels, - self._cg) + cdef int v_int = self.get_vertex(v) cdef set a = set(self.depth_first_search(v)) cdef set b = set(self.depth_first_search(v, reverse=True)) return list(a & b) @@ -2808,7 +2761,6 @@ class CGraphBackend(GenericGraphBackend): ... for i in range(50)) # long time True """ - if not self._directed: raise ValueError("Input must be a directed graph.") @@ -2858,7 +2810,7 @@ class CGraphBackend(GenericGraphBackend): # out-neighbors have been de-activated already, for we put them # *after* u in the stack. if bitset_in(tried, u): - ordering.insert(0, vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)) + ordering.insert(0, self.vertex_label(u)) bitset_discard(tried, u) bitset_discard(activated, u) stack.pop(-1) @@ -2890,12 +2842,12 @@ class CGraphBackend(GenericGraphBackend): # We build it, then return it # // answer = [u] - cycle = [vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)] + cycle = [self.vertex_label(u)] tmp = u while u != uu: u = parent.get(u,uu) - cycle.append(vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)) + cycle.append(self.vertex_label(u)) cycle.reverse() return (False, cycle) @@ -2951,7 +2903,7 @@ cdef class Search_iterator: [0, 1, 4, 5, 2, 6, 3, 9, 7, 8] """ - cdef graph + cdef CGraphBackend graph cdef int direction cdef list stack cdef bitset_t seen @@ -3025,10 +2977,7 @@ cdef class Search_iterator: bitset_init(self.seen, (self.graph._cg).active_vertices.size) bitset_set_first_n(self.seen, 0) - cdef int v_id = get_vertex(v, - self.graph.vertex_ints, - self.graph.vertex_labels, - self.graph._cg) + cdef int v_id = self.graph.get_vertex(v) if v_id == -1: raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(repr(v))) @@ -3078,10 +3027,7 @@ cdef class Search_iterator: v_int = self.stack.pop(self.direction) if bitset_not_in(self.seen, v_int): - value = vertex_label(v_int, - self.graph.vertex_ints, - self.graph.vertex_labels, - self.graph._cg) + value = self.graph.vertex_label(v_int) bitset_add(self.seen, v_int) if self.test_out: diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index 7827e40fef8..6f79bfc323f 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -692,8 +692,7 @@ def _test_adjacency_sequence_out(): # Dense Graph Backend ########################################### -from c_graph import CGraphBackend -from c_graph cimport check_vertex, vertex_label, get_vertex +from c_graph cimport CGraphBackend class DenseGraphBackend(CGraphBackend): """ @@ -774,10 +773,8 @@ class DenseGraphBackend(CGraphBackend): if u is None: u = self.add_vertex(None) if v is None: v = self.add_vertex(None) - cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg, None, 0) - cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg, None, 0) + cdef int u_int = self.check_labelled_vertex(u, 0) + cdef int v_int = self.check_labelled_vertex(v, 0) if directed or u_int == v_int: self._cg.add_arc(u_int, v_int) @@ -845,10 +842,8 @@ class DenseGraphBackend(CGraphBackend): """ if not ( self.has_vertex(u) and self.has_vertex(v) ): return - cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg, None, 0) - cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg, None, 0) + cdef int u_int = self.check_labelled_vertex(u, 0) + cdef int v_int = self.check_labelled_vertex(v, 0) if v is None: u, v = u[:2] if directed: @@ -917,10 +912,8 @@ class DenseGraphBackend(CGraphBackend): """ if not ( self.has_vertex(u) and self.has_vertex(v) ): return False - cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg) - cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + cdef int u_int = self.get_vertex(u) + cdef int v_int = self.get_vertex(v) return self._cg.has_arc(u_int, v_int) def iterator_edges(self, object vertices, bint labels): @@ -943,21 +936,20 @@ class DenseGraphBackend(CGraphBackend): """ cdef object v - vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices if self.has_vertex(v)] + vertices = [self.get_vertex(v) for v in vertices if self.has_vertex(v)] cdef int u_int, v_int if labels: return iter([tuple(sorted( - (vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + (self.vertex_label(v_int), + self.vertex_label(u_int) )))+(None,) for v_int in vertices for u_int in self._cg.out_neighbors(v_int) if u_int >= v_int or u_int not in vertices]) else: return iter([tuple(sorted( - (vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + (self.vertex_label(v_int), + self.vertex_label(u_int) ))) for v_int in vertices for u_int in self._cg.out_neighbors(v_int) @@ -984,20 +976,19 @@ class DenseGraphBackend(CGraphBackend): """ cdef object v - vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices if self.has_vertex(v)] + vertices = [self.get_vertex(v) for v in vertices if self.has_vertex(v)] cdef int u_int, v_int if labels: return iter([ - (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg), + (self.vertex_label(u_int), + self.vertex_label(v_int), None) for v_int in vertices for u_int in self._cg.in_neighbors(v_int)]) else: return iter([ - (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)) + (self.vertex_label(u_int), + self.vertex_label(v_int)) for v_int in vertices for u_int in self._cg.in_neighbors(v_int)]) @@ -1022,20 +1013,19 @@ class DenseGraphBackend(CGraphBackend): """ cdef object u, v - vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices if self.has_vertex(v)] + vertices = [self.get_vertex(v) for v in vertices if self.has_vertex(v)] cdef int u_int, v_int if labels: return iter([ - (vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), + (self.vertex_label(v_int), + self.vertex_label(u_int), None) for v_int in vertices for u_int in self._cg.out_neighbors(v_int)]) else: return iter([ - (vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg), - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)) + (self.vertex_label(v_int), + self.vertex_label(u_int)) for v_int in vertices for u_int in self._cg.out_neighbors(v_int)]) diff --git a/src/sage/graphs/base/sparse_graph.pxd b/src/sage/graphs/base/sparse_graph.pxd index 69630fb7b09..8a15409bbc0 100644 --- a/src/sage/graphs/base/sparse_graph.pxd +++ b/src/sage/graphs/base/sparse_graph.pxd @@ -7,6 +7,7 @@ #******************************************************************************* from c_graph cimport CGraph +from c_graph cimport CGraphBackend cdef struct SparseGraphLLNode: int label diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 6bd4d3d0ded..092593c401e 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1592,9 +1592,6 @@ def _test_adjacency_sequence_out(): # Sparse Graph Backend ########################################### -from c_graph import CGraphBackend -from c_graph cimport get_vertex, check_vertex, vertex_label - cdef int new_edge_label(object l, dict edge_labels): """ Returns a new unique int representing the arbitrary label l. @@ -1693,10 +1690,8 @@ class SparseGraphBackend(CGraphBackend): if u is None: u = self.add_vertex(None) if v is None: v = self.add_vertex(None) - cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg, self._cg_rev, self._directed) - cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg, self._cg_rev, self._directed) + cdef int u_int = self.check_labelled_vertex(u, self._directed) + cdef int v_int = self.check_labelled_vertex(v, self._directed) cdef int l_int if l is None: @@ -1806,10 +1801,8 @@ class SparseGraphBackend(CGraphBackend): """ if not ( self.has_vertex(u) and self.has_vertex(v) ): return - cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg, self._cg_rev, self._directed) - cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg, self._cg_rev, self._directed) + cdef int u_int = self.check_labelled_vertex(u, self._directed) + cdef int v_int = self.check_labelled_vertex(v, self._directed) if l is None: if self._cg.has_arc_label(u_int, v_int, 0): @@ -1857,10 +1850,8 @@ class SparseGraphBackend(CGraphBackend): raise LookupError("({0}) is not a vertex of the graph.".format(repr(u))) if not self.has_vertex(v): raise LookupError("({0}) is not a vertex of the graph.".format(repr(v))) - cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg) - cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + cdef int u_int = self.get_vertex(u) + cdef int v_int = self.get_vertex(v) if not (self._cg).has_arc_unsafe(u_int, v_int): raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u),repr(v))) if self.multiple_edges(None): @@ -1890,10 +1881,8 @@ class SparseGraphBackend(CGraphBackend): """ if not ( self.has_vertex(u) and self.has_vertex(v) ): return False - cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg) - cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + cdef int u_int = self.get_vertex(u) + cdef int v_int = self.get_vertex(v) if l is None: return self._cg.has_arc(u_int, v_int) for l_int in self.edge_labels: @@ -1940,60 +1929,54 @@ class SparseGraphBackend(CGraphBackend): if not isinstance(vertices, list): if labels: for v in self.iterator_verts(): - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + v_int = self.get_vertex(v) for u_int, l_int in ( self._cg).out_arcs_unsafe(v_int, True): if u_int >= v_int: - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) l = self.edge_labels[l_int] if l_int else None yield (v, u, l) if v<=u else (u, v, l) else: for v in self.iterator_verts(): - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + v_int = self.get_vertex(v) for u_int in ( self._cg).out_arcs_unsafe(v_int, False): if u_int >= v_int: - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) yield (v, u) if v <= u else (u, v) # One vertex elif len(vertices) == 1: v = vertices[0] - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + v_int = self.get_vertex(v) if labels: for u_int, l_int in ( self._cg).out_arcs_unsafe(v_int, True): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) l = self.edge_labels[l_int] if l_int else None yield (v, u, l) if v<=u else (u, v, l) else: for u_int in ( self._cg).out_arcs_unsafe(v_int, False): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) yield (v, u) if v <= u else (u, v) # Several vertices (nonempty list) elif vertices: - b_vertices = FrozenBitset([get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices]) + b_vertices = FrozenBitset([self.get_vertex(v) for v in vertices]) if labels: for v in vertices: - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + v_int = self.get_vertex(v) for u_int, l_int in ( self._cg).out_arcs_unsafe(v_int, True): if u_int >= v_int or u_int not in b_vertices: - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) l = self.edge_labels[l_int] if l_int else None yield (v, u, l) if v<=u else (u, v, l) else: for v in vertices: - v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + v_int = self.get_vertex(v) for u_int in ( self._cg).out_arcs_unsafe(v_int, False): if u_int >= v_int or u_int not in b_vertices: - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) yield (v, u) if v <= u else (u, v) def iterator_in_edges(self, object vertices, bint labels): @@ -2018,37 +2001,36 @@ class SparseGraphBackend(CGraphBackend): """ cdef object u, v, L, l - vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices if self.has_vertex(v)] + vertices = [self.get_vertex(v) for v in vertices if self.has_vertex(v)] cdef int u_int, v_int, l_int if self.multiple_edges(None): if labels: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int, l_int in ( self._cg_rev).out_arcs_unsafe(v_int, True): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) l = self.edge_labels[l_int] if l_int else None yield (u, v, l) else: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in ( self._cg_rev).out_arcs_unsafe(v_int, False): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) yield (u, v) else: if labels: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in self._cg_rev.out_neighbors(v_int): l_int = self._cg.arc_label(u_int, v_int) - yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), + yield (self.vertex_label(u_int), v, None if l_int == 0 else self.edge_labels[l_int]) else: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in self._cg_rev.out_neighbors(v_int): - yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), + yield (self.vertex_label(u_int), v) def iterator_out_edges(self, object vertices, bint labels): @@ -2072,38 +2054,37 @@ class SparseGraphBackend(CGraphBackend): """ cdef object u, v, L, l - vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) for v in vertices if self.has_vertex(v)] + vertices = [self.get_vertex(v) for v in vertices if self.has_vertex(v)] cdef int u_int, v_int, l_int if self.multiple_edges(None): if labels: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int, l_int in ( self._cg).out_arcs_unsafe(v_int, True): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) l = self.edge_labels[l_int] if l_int else None yield (v, u, l) else: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in ( self._cg).out_arcs_unsafe(v_int, False): - u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg) + u = self.vertex_label(u_int) yield (v, u) else: if labels: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in self._cg.out_neighbors(v_int): l_int = self._cg.arc_label(v_int, u_int) yield (v, - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg), + self.vertex_label(u_int), None if l_int == 0 else self.edge_labels[l_int]) else: for v_int in vertices: - v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg) + v = self.vertex_label(v_int) for u_int in self._cg.out_neighbors(v_int): yield (v, - vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)) + self.vertex_label(u_int)) def multiple_edges(self, new): """ @@ -2168,10 +2149,8 @@ class SparseGraphBackend(CGraphBackend): l_int = 0 else: l_int = new_edge_label(l, self.edge_labels) - cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels, - self._cg) - cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, - self._cg) + cdef int u_int = self.get_vertex(u) + cdef int v_int = self.get_vertex(v) if not (self._cg).has_arc_unsafe(u_int, v_int): return ll_int = (self._cg).arc_label_unsafe(u_int, v_int) diff --git a/src/sage/graphs/base/static_sparse_backend.pxd b/src/sage/graphs/base/static_sparse_backend.pxd index 1e76cf7f051..6e4c3b09acc 100644 --- a/src/sage/graphs/base/static_sparse_backend.pxd +++ b/src/sage/graphs/base/static_sparse_backend.pxd @@ -1,6 +1,6 @@ from c_graph cimport CGraph from static_sparse_graph cimport short_digraph, ushort -from c_graph import CGraphBackend +from c_graph cimport CGraphBackend cdef class StaticSparseCGraph(CGraph): cdef short_digraph g diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 7eed8a2eaac..5f88c8a5b56 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -37,7 +37,7 @@ from sage.graphs.base.static_sparse_graph cimport (init_short_digraph, has_edge, free_short_digraph, edge_label) -from c_graph import CGraphBackend +from c_graph cimport CGraphBackend from sage.data_structures.bitset cimport FrozenBitset from libc.stdint cimport uint32_t include 'sage/data_structures/bitset.pxi' diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 915bb2265de..6cf09b9c522 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -161,6 +161,7 @@ cimport cpython from sage.graphs.base.c_graph cimport CGraph from libc.stdint cimport INT32_MAX from static_sparse_backend cimport StaticSparseCGraph +from static_sparse_backend cimport StaticSparseBackend cdef int init_short_digraph(short_digraph g, G, edge_labelled = False) except -1: r""" diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index c21a28cc221..ba7aac02c70 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -145,9 +145,8 @@ Functions include "sage/data_structures/binary_matrix.pxi" from libc.stdint cimport uint64_t, uint32_t, INT32_MAX, UINT32_MAX +from sage.graphs.base.c_graph cimport CGraphBackend from sage.graphs.base.c_graph cimport CGraph -from sage.graphs.base.c_graph cimport vertex_label -from sage.graphs.base.c_graph cimport get_vertex from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph @@ -360,13 +359,13 @@ def shortest_path_all_pairs(G): cdef dict d = {} cdef dict d_tmp - cdef CGraph cg = G._backend._cg + cdef CGraphBackend cg = G._backend cdef list int_to_vertex = G.vertices() cdef int i, j for i, l in enumerate(int_to_vertex): - int_to_vertex[i] = get_vertex(l, G._backend.vertex_ints, G._backend.vertex_labels, cg) + int_to_vertex[i] = cg.get_vertex(l) for j in range(n): d_tmp = {} @@ -1591,21 +1590,20 @@ def floyd_warshall(gg, paths = True, distances = False): cdef dict tmp_prec cdef dict tmp_dist - cdef dict ggbvi = gg._backend.vertex_ints - cdef dict ggbvl = gg._backend.vertex_labels + cdef CGraphBackend cgb = gg._backend if paths: d_prec = {} if distances: d_dist = {} for v_int in gverts: if paths: tmp_prec = {} if distances: tmp_dist = {} - v = vertex_label(v_int, ggbvi, ggbvl, g) + v = cgb.vertex_label(v_int) dv = dist[v_int] for u_int in gverts: - u = vertex_label(u_int, ggbvi, ggbvl, g) + u = cgb.vertex_label(u_int) if paths: tmp_prec[u] = (None if v == u - else vertex_label(prec[v_int][u_int], ggbvi, ggbvl, g)) + else cgb.vertex_label(prec[v_int][u_int])) if distances: tmp_dist[u] = (dv[u_int] if (dv[u_int] != -1) else Infinity) From 2704dda485adcd6f4e7a6a951b1380dca3ae768b Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 10:23:43 +0200 Subject: [PATCH 619/665] trac #18346: Turn the backends into cdef classes --- src/sage/graphs/base/c_graph.pxd | 16 +++++++++++--- src/sage/graphs/base/c_graph.pyx | 21 +++++++------------ src/sage/graphs/base/dense_graph.pyx | 11 +++++----- src/sage/graphs/base/sparse_graph.pxd | 3 +++ src/sage/graphs/base/sparse_graph.pyx | 13 ++++++------ .../graphs/base/static_sparse_backend.pxd | 6 ++++++ .../graphs/base/static_sparse_backend.pyx | 6 +++--- src/sage/graphs/base/static_sparse_graph.pyx | 2 +- 8 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pxd b/src/sage/graphs/base/c_graph.pxd index b2e38cf9645..39fa6070449 100644 --- a/src/sage/graphs/base/c_graph.pxd +++ b/src/sage/graphs/base/c_graph.pxd @@ -6,6 +6,7 @@ #************************************************************************** from sage.data_structures.bitset cimport bitset_t +from graph_backends cimport GenericGraphBackend cdef class CGraph: cdef int num_verts @@ -39,9 +40,18 @@ cdef class CGraph: cpdef realloc(self, int) cdef int add_vertex_unsafe(self, int) except -1 -cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels, CGraph G) except ? -2 -cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels, CGraph G) -cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels, CGraph G, CGraph G_revx, bint reverse) except ? -1 +cdef class CGraphBackend(GenericGraphBackend): + cdef int get_vertex(self, object u) except ? -2 + cdef object vertex_label(self, int u_int) + cdef int check_labelled_vertex(self, object u, bint reverse) except ? -1 + cdef CGraph _cg + cdef CGraph _cg_rev + cdef bint _directed + cdef dict vertex_labels + cdef dict vertex_ints + cdef dict edge_labels + cdef bint _loops + cdef bint _multiple_edges # TODO: edge functions! diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 706b7877aec..e2e2fb96e29 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -39,7 +39,6 @@ method :meth:`realloc `. include "sage/data_structures/bitset.pxi" -from graph_backends import GenericGraphBackend from sage.rings.integer cimport Integer cdef class CGraph: @@ -1115,7 +1114,7 @@ cdef class CGraph: """ return self.num_arcs -class CGraphBackend(GenericGraphBackend): +cdef class CGraphBackend(GenericGraphBackend): """ Base class for sparse and dense graph backends. @@ -1136,7 +1135,7 @@ class CGraphBackend(GenericGraphBackend): sage: CGB.degree(0, True) Traceback (most recent call last): ... - AttributeError: 'CGraphBackend' object has no attribute 'vertex_ints' + TypeError: 'NoneType' object is not iterable The appropriate way to use these backends is via Sage graphs:: @@ -1154,10 +1153,6 @@ class CGraphBackend(GenericGraphBackend): -- backend for dense graphs. """ - _cg = None - _cg_rev = None - _directed = None - cdef int get_vertex(self, object u) except ? -2: """ Returns an int representing the arbitrary hashable vertex u (whether or not @@ -1941,23 +1936,23 @@ class CGraphBackend(GenericGraphBackend): 2 sage: from sage.graphs.base.sparse_graph import SparseGraphBackend sage: S = SparseGraphBackend(7) - sage: S.num_edges(directed=False) + sage: S.num_edges(False) 0 sage: S.loops(True) sage: S.add_edge(1, 1, None, directed=False) - sage: S.num_edges(directed=False) + sage: S.num_edges(False) 1 sage: S.multiple_edges(True) sage: S.add_edge(1, 1, None, directed=False) - sage: S.num_edges(directed=False) + sage: S.num_edges(False) 2 sage: from sage.graphs.base.dense_graph import DenseGraphBackend sage: D = DenseGraphBackend(7) - sage: D.num_edges(directed=False) + sage: D.num_edges(False) 0 sage: D.loops(True) sage: D.add_edge(1, 1, None, directed=False) - sage: D.num_edges(directed=False) + sage: D.num_edges(False) 1 """ if directed: @@ -2974,7 +2969,7 @@ cdef class Search_iterator: self.graph = graph self.direction = direction - bitset_init(self.seen, (self.graph._cg).active_vertices.size) + bitset_init(self.seen, self.graph._cg.active_vertices.size) bitset_set_first_n(self.seen, 0) cdef int v_id = self.graph.get_vertex(v) diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index 6f79bfc323f..4b79a398f92 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -234,13 +234,14 @@ cdef class DenseGraph(CGraph): """ from sage.graphs.all import DiGraph D = DiGraph(implementation='c_graph', sparse=False) - D._backend._cg = self + cdef CGraphBackend cgb = D._backend + cgb._cg = self cdef int i - D._backend.vertex_labels = {} + cgb.vertex_labels = {} for i from 0 <= i < self.active_vertices.size: if bitset_in(self.active_vertices, i): - D._backend.vertex_labels[i] = i - D._backend.vertex_ints = D._backend.vertex_labels + cgb.vertex_labels[i] = i + cgb.vertex_ints = cgb.vertex_labels return (DenseGraph, (0, self.active_vertices.size, self.verts(), D.edges(labels=False))) cpdef realloc(self, int total_verts): @@ -694,7 +695,7 @@ def _test_adjacency_sequence_out(): from c_graph cimport CGraphBackend -class DenseGraphBackend(CGraphBackend): +cdef class DenseGraphBackend(CGraphBackend): """ Backend for Sage graphs using DenseGraphs. diff --git a/src/sage/graphs/base/sparse_graph.pxd b/src/sage/graphs/base/sparse_graph.pxd index 8a15409bbc0..84e4c2a3372 100644 --- a/src/sage/graphs/base/sparse_graph.pxd +++ b/src/sage/graphs/base/sparse_graph.pxd @@ -39,4 +39,7 @@ cdef class SparseGraph(CGraph): cdef int out_neighbors_BTNode_unsafe(self, int u, SparseGraphBTNode *** p_pointers) cdef list out_arcs_unsafe(self, int u, bint labels) +cdef class SparseGraphBackend(CGraphBackend): + pass + cdef int new_edge_label(object l, dict edge_labels) diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 092593c401e..1f522d9c146 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -415,14 +415,15 @@ cdef class SparseGraph(CGraph): """ from sage.graphs.all import DiGraph D = DiGraph(implementation='c_graph', sparse=True, multiedges=True, loops=True) - D._backend._cg = self + cdef CGraphBackend cgb = D._backend + cgb._cg = self cdef int i - D._backend.vertex_labels = {} + cgb.vertex_labels = {} for i from 0 <= i < self.active_vertices.size: if bitset_in(self.active_vertices, i): - D._backend.vertex_labels[i] = i - D._backend.vertex_ints = D._backend.vertex_labels - D._backend.edge_labels = id_dict() + cgb.vertex_labels[i] = i + cgb.vertex_ints = cgb.vertex_labels + cgb.edge_labels = id_dict() arcs = [(u,v,l) if l is not None else (u,v,0) for u,v,l in D.edges(labels=True)] return (SparseGraph, (0, self.hash_length, self.active_vertices.size, self.verts(), arcs)) @@ -1605,7 +1606,7 @@ cdef int new_edge_label(object l, dict edge_labels): edge_labels[max+1] = l return max+1 -class SparseGraphBackend(CGraphBackend): +cdef class SparseGraphBackend(CGraphBackend): """ Backend for Sage graphs using SparseGraphs. diff --git a/src/sage/graphs/base/static_sparse_backend.pxd b/src/sage/graphs/base/static_sparse_backend.pxd index 6e4c3b09acc..c60d6f8f19b 100644 --- a/src/sage/graphs/base/static_sparse_backend.pxd +++ b/src/sage/graphs/base/static_sparse_backend.pxd @@ -10,3 +10,9 @@ cdef class StaticSparseCGraph(CGraph): cpdef int out_degree(self, int u) except -1 cpdef int in_degree(self, int u) except -1 + +cdef class StaticSparseBackend(CGraphBackend): + cdef int _order + cdef bint _multiedges + cdef list _vertex_to_labels + cdef dict _vertex_to_int diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 5f88c8a5b56..d62d95bbb8d 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -323,7 +323,7 @@ cdef class StaticSparseCGraph(CGraph): else: return self.g_rev.neighbors[u+1] - self.g_rev.neighbors[u] -class StaticSparseBackend(CGraphBackend): +cdef class StaticSparseBackend(CGraphBackend): def __init__(self, G, loops = False, multiedges=False): """ @@ -1136,9 +1136,9 @@ def _run_it_on_static_instead(f): sage: Graph.new_graph_method = new_graph_method sage: g = Graph(5) sage: print "My backend is of type", g._backend - My backend is of type + My backend is of type sage: g.new_graph_method() - My backend is of type + My backend is of type """ def same_function_on_static_version(*kwd,**kwds): if not isinstance(kwd[0]._backend,StaticSparseBackend): diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 6cf09b9c522..405bcdd55f6 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -517,7 +517,7 @@ def triangles_count(G): # g is a copy of G. If G is internally a static sparse graph, we use it. cdef short_digraph g G = G.copy(immutable=True) - g[0] = ( (G._backend._cg)).g[0] + g[0] = ( ( G._backend)._cg).g[0] cdef uint64_t count = 0 cdef uint32_t u,v,i From e11d4d8c3d91923e770fdba9310d832415236b1e Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 08:13:42 +0200 Subject: [PATCH 620/665] trac #18346: New pickling function for GraphBackend --- src/sage/graphs/base/graph_backends.pyx | 95 +++++++++++++++++++ .../graphs/base/static_sparse_backend.pyx | 1 + 2 files changed, 96 insertions(+) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 917dc24e246..60d5f7c346c 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -9,6 +9,8 @@ Implements various backends for Sage graphs. # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #******************************************************************************* +from c_graph cimport CGraphBackend +from c_graph cimport CGraph cdef class GenericGraphBackend(SageObject): """ @@ -579,6 +581,99 @@ cdef class GenericGraphBackend(SageObject): """ raise NotImplementedError() + def __reduce__(self): + r"""" + Return a tuple used for pickling this graph. + + This function returns a pair ``(f, args)`` such that ``f(*args)`` + produces a copy of ``self``. The function returned is always + :func:`unpickle_graph_backend`. + + """ + from static_sparse_backend import StaticSparseBackend + from sparse_graph import SparseGraphBackend + from dense_graph import DenseGraphBackend + + # implementation, data_structure, multiedges, directed, loops + if isinstance(self, CGraphBackend): + implementation = "c_graph" + if isinstance(self,SparseGraphBackend): + data_structure = "sparse" + elif isinstance(self,DenseGraphBackend): + data_structure = "dense" + elif isinstance(self,StaticSparseBackend): + implementaton = "static_sparse" + else: + raise Exception + multiedges = ( self)._multiple_edges + directed = ( self)._directed + loops = ( self)._loops + elif isinstance(self, NetworkXGraphBackend): + data_structure = "implementation" + implementation = "networkx" + multiedges = self._nxg.is_multigraph() + directed = self._nxg.is_directed() + loops = bool(self._nxg.number_of_selfloops) + else: + raise Exception + + # Vertices and edges + vertices = list(self.iterator_verts(None)) + if directed: + edges = list(self.iterator_out_edges(vertices,True)) + else: + edges = list(self.iterator_edges(vertices,True)) + + return (unpickle_graph_backend, + (directed, vertices, edges, + {'loops': loops, + 'multiedges': multiedges})) + +def unpickle_graph_backend(directed,vertices,edges,kwds): + r""" + Return a backend from its pickled data + + This methods is defined because Python's pickling mechanism can only build + objects from a pair ``(f,args)`` by running ``f(*args)``. In particular, + there is apparently no way to define a ``**kwargs`` (i.e. define the value + of keyword arguments of ``f``), which means that one must know the order of + all arguments of ``f`` (here, ``f`` is :class:`Graph` or :class:`DiGraph`). + + As a consequence, this means that the order cannot change in the future, + which is something we cannot swear. + + INPUT: + + - ``directed`` (boolean) + + - ``vertices`` -- list of vertices. + + - ``edges`` -- list of edges + + - ``kwds`` -- any dictionary whose keywords will be forwarded to the graph + constructor. + + This function builds a :class:`Graph` or :class:`DiGraph` from its data, and + returns the ``_backend`` attribute of this object. + + EXAMPLE:: + + sage: from sage.graphs.base.graph_backends import unpickle_graph_backend + sage: b = unpickle_graph_backend(0,[0,1,2,3],[(0,3,'label'),(0,0,1)],{'loops':True}) + sage: b + + sage: list(b.iterator_edges(range(4),1)) + [(0, 0, 1), (0, 3, 'label')] + """ + if directed: + from sage.graphs.digraph import DiGraph as constructor + else: + from sage.graphs.graph import Graph as constructor + + G = constructor(data=edges,**kwds) + G.add_vertices(vertices) + return G._backend + class NetworkXGraphDeprecated(SageObject): """ Class for unpickling old networkx.XGraph formats diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index d62d95bbb8d..aaca2324ae7 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -426,6 +426,7 @@ cdef class StaticSparseBackend(CGraphBackend): # vertex_labels (which is a dictionary) self.vertex_ints = self._vertex_to_int self.vertex_labels = {i:v for i,v in enumerate(vertices)} + self._multiple_edges = self._multiedges def __reduce__(self): """ From bd8d988e0692b0089770f231e9c36e526bb077ad Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 08:33:56 +0200 Subject: [PATCH 621/665] trac #18346: Remove old __reduce__ functions and move useful doctests --- src/sage/graphs/base/dense_graph.pyx | 32 ------- src/sage/graphs/base/graph_backends.pyx | 35 ++++++++ src/sage/graphs/base/sparse_graph.pyx | 86 ------------------- .../graphs/base/static_sparse_backend.pyx | 54 ------------ 4 files changed, 35 insertions(+), 172 deletions(-) diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index 4b79a398f92..afeb2ec91d5 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -212,38 +212,6 @@ cdef class DenseGraph(CGraph): sage_free(self.out_degrees) bitset_free(self.active_vertices) - def __reduce__(self): - """ - Return a tuple used for pickling this graph. - - TESTS:: - - sage: from sage.graphs.base.dense_graph import DenseGraph - sage: D = DenseGraph(nverts = 10, extra_vertices = 10) - sage: D.add_arc(0,1) - sage: D.has_arc(0,1) - 1 - sage: D.has_arc(1,2) - 0 - sage: LD = loads(dumps(D)) - sage: LD.has_arc(0,1) - 1 - sage: LD.has_arc(1,2) - 0 - - """ - from sage.graphs.all import DiGraph - D = DiGraph(implementation='c_graph', sparse=False) - cdef CGraphBackend cgb = D._backend - cgb._cg = self - cdef int i - cgb.vertex_labels = {} - for i from 0 <= i < self.active_vertices.size: - if bitset_in(self.active_vertices, i): - cgb.vertex_labels[i] = i - cgb.vertex_ints = cgb.vertex_labels - return (DenseGraph, (0, self.active_vertices.size, self.verts(), D.edges(labels=False))) - cpdef realloc(self, int total_verts): """ Reallocate the number of vertices to use, without actually adding any. diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 60d5f7c346c..4fd0551dffd 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -589,6 +589,41 @@ cdef class GenericGraphBackend(SageObject): produces a copy of ``self``. The function returned is always :func:`unpickle_graph_backend`. + Pickling of the static graph backend makes pickling of immutable + graphs and digraphs work:: + + sage: G = Graph(graphs.PetersenGraph(), immutable=True) + sage: G == loads(dumps(G)) + True + sage: uc = [[2,3], [], [1], [1], [1], [3,4]] + sage: D = DiGraph(dict([[i,uc[i]] for i in range(len(uc))]), immutable=True) + sage: loads(dumps(D)) == D + True + + No problems with loops and multiple edges, with Labels:: + + sage: g = Graph(multiedges = True, loops = True) + sage: g.add_edges(2*graphs.PetersenGraph().edges()) + sage: g.add_edge(0,0) + sage: g.add_edge(1,1, "a label") + sage: g.add_edge([(0,1,"labellll"), (0,1,"labellll"), (0,1,"LABELLLL")]) + sage: g.add_vertex("isolated vertex") + sage: gi = g.copy(immutable=True) + sage: loads(dumps(gi)) == gi + True + + Similar, with a directed graph:: + + sage: g = DiGraph(multiedges = True, loops = True) + sage: H = 2*(digraphs.Circuit(15)+DiGraph(graphs.PetersenGraph())) + sage: g.add_edges(H.edges()) + sage: g.add_edge(0,0) + sage: g.add_edge(1,1, "a label") + sage: g.add_edge([(0,1,"labellll"), (0,1,"labellll"), (0,1,"LABELLLL")]) + sage: g.add_vertex("isolated vertex") + sage: gi = g.copy(immutable=True) + sage: loads(dumps(gi)) == gi + True """ from static_sparse_backend import StaticSparseBackend from sparse_graph import SparseGraphBackend diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 1f522d9c146..90c78086564 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -210,45 +210,6 @@ cdef inline int compare(int a, int b): return -1 return 0 -class id_dict: - """ - This is a helper class for pickling sparse graphs. It emulates a dictionary - ``d`` which contains all objects, and always, ``d[x] == x``. - - EXAMPLE:: - - sage: from sage.graphs.base.sparse_graph import id_dict - sage: d = id_dict() - sage: d[None] is None - True - sage: d[7] - 7 - sage: d[{}] - {} - sage: d[()] - () - - """ - def __getitem__(self, x): - """ - Implements d[x]. - - EXAMPLE: - - sage: from sage.graphs.base.sparse_graph import id_dict - sage: d = id_dict() - sage: d[None] is None - True - sage: d[7] - 7 - sage: d[{}] - {} - sage: d[()] - () - - """ - return x - cdef class SparseGraph(CGraph): """ Compiled sparse graphs. @@ -380,53 +341,6 @@ cdef class SparseGraph(CGraph): sage_free(self.out_degrees) bitset_free(self.active_vertices) - def __reduce__(self): - """ - Return a tuple used for pickling this graph. - - TESTS:: - - sage: from sage.graphs.base.sparse_graph import SparseGraph - sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10) - sage: S.add_arc(0,1) - sage: S.add_arc(0,1) - sage: S.all_arcs(0,1) - [0, 0] - sage: S.all_arcs(1,2) - [] - sage: S.add_arc_label(0,0,3) - sage: S.all_arcs(0,0) - [3] - sage: LS = loads(dumps(S)) - sage: LS.all_arcs(0,1) - [0, 0] - sage: LS.all_arcs(1,2) - [] - sage: LS.all_arcs(0,0) - [3] - - Test for the trac 10916 -- are multiedges and loops pickled - correctly?:: - - sage: DG = DiGraph({0:{0:[0, 1], 1:[0, 1]}}) - sage: loads(dumps(DG)).edges() - [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)] - - """ - from sage.graphs.all import DiGraph - D = DiGraph(implementation='c_graph', sparse=True, multiedges=True, loops=True) - cdef CGraphBackend cgb = D._backend - cgb._cg = self - cdef int i - cgb.vertex_labels = {} - for i from 0 <= i < self.active_vertices.size: - if bitset_in(self.active_vertices, i): - cgb.vertex_labels[i] = i - cgb.vertex_ints = cgb.vertex_labels - cgb.edge_labels = id_dict() - arcs = [(u,v,l) if l is not None else (u,v,0) for u,v,l in D.edges(labels=True)] - return (SparseGraph, (0, self.hash_length, self.active_vertices.size, self.verts(), arcs)) - cpdef realloc(self, int total): """ Reallocate the number of vertices to use, without actually adding any. diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index aaca2324ae7..9e8ad2ccdc0 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -428,60 +428,6 @@ cdef class StaticSparseBackend(CGraphBackend): self.vertex_labels = {i:v for i,v in enumerate(vertices)} self._multiple_edges = self._multiedges - def __reduce__(self): - """ - Return a tuple used for pickling this graph. - - TESTS: - - Pickling of the static graph backend makes pickling of immutable - graphs and digraphs work:: - - sage: G = Graph(graphs.PetersenGraph(), immutable=True) - sage: G == loads(dumps(G)) - True - sage: uc = [[2,3], [], [1], [1], [1], [3,4]] - sage: D = DiGraph(dict([[i,uc[i]] for i in range(len(uc))]), immutable=True) - sage: loads(dumps(D)) == D - True - - No problems with loops and multiple edges, with Labels:: - - sage: g = Graph(multiedges = True, loops = True) - sage: g.add_edges(2*graphs.PetersenGraph().edges()) - sage: g.add_edge(0,0) - sage: g.add_edge(1,1, "a label") - sage: g.add_edge([(0,1,"labellll"), (0,1,"labellll"), (0,1,"LABELLLL")]) - sage: g.add_vertex("isolated vertex") - sage: gi = g.copy(immutable=True) - sage: loads(dumps(gi)) == gi - True - - Similar, with a directed graph:: - - sage: g = DiGraph(multiedges = True, loops = True) - sage: H = 2*(digraphs.Circuit(15)+DiGraph(graphs.PetersenGraph())) - sage: g.add_edges(H.edges()) - sage: g.add_edge(0,0) - sage: g.add_edge(1,1, "a label") - sage: g.add_edge([(0,1,"labellll"), (0,1,"labellll"), (0,1,"LABELLLL")]) - sage: g.add_vertex("isolated vertex") - sage: gi = g.copy(immutable=True) - sage: loads(dumps(gi)) == gi - True - """ - if self._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=self._loops, multiedges=self._multiedges) - G.add_edges(list(self.iterator_out_edges(self.iterator_verts(None),True))) - else: - from sage.graphs.graph import Graph - G = Graph(loops=self._loops, multiedges=self._multiedges) - G.add_edges(list(self.iterator_edges(self.iterator_verts(None),True))) - - G.add_vertices(self.iterator_verts(None)) - return (StaticSparseBackend, (G, self._loops, self._multiedges)) - def has_vertex(self, v): r""" Tests if the vertex belongs to the graph From 30eb6263d2f532d602a5479057542dee640e1dbd Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 09:15:51 +0200 Subject: [PATCH 622/665] trac #18346: Some python code accesses G._backend._cg directly --- src/sage/graphs/base/c_graph.pyx | 14 ++++++++++++++ src/sage/graphs/distances_all_pairs.pyx | 2 +- src/sage/graphs/generic_graph.py | 12 ++++++------ src/sage/graphs/genus.pyx | 22 +++++++++++----------- src/sage/graphs/trees.pyx | 3 ++- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index e2e2fb96e29..3fb4bdd3332 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1284,6 +1284,20 @@ cdef class CGraphBackend(GenericGraphBackend): return False return True + def c_graph(self): + r""" + Return the ``._cg`` and ``._cg_rev`` attributes + + EXAMPLES:: + + sage: cg,cg_rev = graphs.PetersenGraph()._backend.c_graph() + sage: cg + + sage: cg_rev + + """ + return (self._cg, self._cg_rev) + def degree(self, v, directed): """ Return the degree of the vertex ``v``. diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index ba7aac02c70..cbb7afdf2f5 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1498,7 +1498,7 @@ def floyd_warshall(gg, paths = True, distances = False): """ from sage.rings.infinity import Infinity - cdef CGraph g = gg._backend._cg + cdef CGraph g = gg._backend.c_graph()[0] cdef list gverts = g.verts() diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c5c58435c9f..ee71616aead 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17745,7 +17745,7 @@ def automorphism_group(self, partition=None, verbosity=0, for u,v in G.edge_iterator(labels=False): u = G_to[u]; v = G_to[v] HB.add_edge(u,v,None,G._directed) - GC = HB._cg + GC = HB.c_graph()[0] partition = [[G_to[v] for v in cell] for cell in partition] A = search_tree(GC, partition, lab=False, dict_rep=True, dig=dig, verbosity=verbosity, order=order) if order: @@ -17792,7 +17792,7 @@ def automorphism_group(self, partition=None, verbosity=0, for u,v in self.edge_iterator(labels=False): u = G_to[u]; v = G_to[v] HB.add_edge(u,v,None,self._directed) - GC = HB._cg + GC = HB.c_graph()[0] partition = [[G_to[v] for v in cell] for cell in partition] if return_group: @@ -18210,7 +18210,7 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, al for u,v in G.edge_iterator(labels=False): u = G_to[u]; v = G_to[v] HB.add_edge(u,v,None,G._directed) - G = HB._cg + G = HB.c_graph()[0] partition = [[G_to[v] for v in cell] for cell in partition] GC = G G2_to = {} @@ -18221,7 +18221,7 @@ def is_isomorphic(self, other, certify=False, verbosity=0, edge_labels=False, al for u,v in G2.edge_iterator(labels=False): u = G2_to[u]; v = G2_to[v] H2B.add_edge(u,v,None,G2._directed) - G2 = H2B._cg + G2 = H2B.c_graph()[0] partition2 = [G2_to[v] for v in partition2] GC2 = G2 isom = isomorphic(GC, GC2, partition, partition2, (self._directed or self.has_loops()), 1) @@ -18391,7 +18391,7 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, for u,v in G.edge_iterator(labels=False): u = G_to[u]; v = G_to[v] HB.add_edge(u,v,None,G._directed) - GC = HB._cg + GC = HB.c_graph()[0] partition = [[G_to[v] for v in cell] for cell in partition] a,b,c = search_tree(GC, partition, certify=True, dig=dig, verbosity=verbosity) # c is a permutation to the canonical label of G, which depends only on isomorphism class of self. @@ -18415,7 +18415,7 @@ def canonical_label(self, partition=None, certify=False, verbosity=0, for u,v in self.edge_iterator(labels=False): u = G_to[u]; v = G_to[v] HB.add_edge(u,v,None,self._directed) - GC = HB._cg + GC = HB.c_graph()[0] partition = [[G_to[v] for v in cell] for cell in partition] a,b,c = search_tree(GC, partition, certify=True, dig=dig, verbosity=verbosity) H = copy(self) diff --git a/src/sage/graphs/genus.pyx b/src/sage/graphs/genus.pyx index 7aec64fa436..a8aed09ed11 100644 --- a/src/sage/graphs/genus.pyx +++ b/src/sage/graphs/genus.pyx @@ -87,19 +87,19 @@ cdef class simple_connected_genus_backtracker: sage: import sage.graphs.genus sage: G = graphs.CompleteGraph(6) sage: G = Graph(G, implementation='c_graph', sparse=False) - sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: bt.genus() #long time 1 sage: bt.genus(cutoff=1) 1 sage: G = graphs.PetersenGraph() sage: G = Graph(G, implementation='c_graph', sparse=False) - sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: bt.genus() 1 sage: G = graphs.FlowerSnark() sage: G = Graph(G, implementation='c_graph', sparse=False) - sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: bt = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: bt.genus() 2 @@ -161,9 +161,9 @@ cdef class simple_connected_genus_backtracker: TESTS:: sage: import sage.graphs.genus sage: G = Graph(implementation='c_graph', sparse=False) #indirect doctest - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: G = Graph(graphs.CompleteGraph(4), implementation='c_graph', sparse=False) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.genus() 0 @@ -285,18 +285,18 @@ cdef class simple_connected_genus_backtracker: sage: import sage.graphs.genus sage: G = Graph(graphs.CompleteGraph(5), implementation='c_graph', sparse=False) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.genus(record_embedding = True) 1 sage: gb.get_embedding() {0: [1, 2, 3, 4], 1: [0, 2, 3, 4], 2: [0, 1, 4, 3], 3: [0, 2, 1, 4], 4: [0, 3, 1, 2]} sage: G = Graph(implementation='c_graph', sparse=False) sage: G.add_edge(0,1) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.get_embedding() {0: [1], 1: [0]} sage: G = Graph(implementation='c_graph', sparse=False) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.get_embedding() {} @@ -517,7 +517,7 @@ cdef class simple_connected_genus_backtracker: sage: import sage.graphs.genus sage: G = Graph(graphs.CompleteGraph(5), implementation='c_graph', sparse=False) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.genus(cutoff = 2, record_embedding = True) 2 sage: E = gb.get_embedding() @@ -528,7 +528,7 @@ cdef class simple_connected_genus_backtracker: sage: gb.genus(style=2, cutoff=5) 3 sage: G = Graph(implementation='c_graph', sparse=False) - sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend._cg) + sage: gb = sage.graphs.genus.simple_connected_genus_backtracker(G._backend.c_graph()[0]) sage: gb.genus() 0 @@ -704,7 +704,7 @@ def simple_connected_graph_genus(G, set_embedding = False, check = True, minimal G, vmap = G.relabel(inplace=False,return_map=True) backmap = dict([(u,v) for (v,u) in vmap.items()]) G = Graph(G, implementation = 'c_graph', sparse=False) - GG = simple_connected_genus_backtracker(G._backend._cg) + GG = simple_connected_genus_backtracker(G._backend.c_graph()[0]) if minimal: style = 1 diff --git a/src/sage/graphs/trees.pyx b/src/sage/graphs/trees.pyx index 75de080bfb9..037aa0b31bb 100644 --- a/src/sage/graphs/trees.pyx +++ b/src/sage/graphs/trees.pyx @@ -24,6 +24,7 @@ include "sage/ext/stdsage.pxi" from sage.graphs.graph import Graph from sage.graphs.base.sparse_graph cimport SparseGraph +from sage.graphs.base.sparse_graph cimport SparseGraphBackend cdef class TreeIterator: r""" @@ -177,7 +178,7 @@ cdef class TreeIterator: # though it is twice as fast (for our purposes) as networkx. G = Graph(self.vertices, implementation='c_graph', sparse=True) - cdef SparseGraph SG = G._backend._cg + cdef SparseGraph SG = ( G._backend)._cg for i from 2 <= i <= self.vertices: vertex1 = i - 1 From 25765bb3c4cb4c5f49e5078d7e6e3968c62310e1 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 09:18:41 +0200 Subject: [PATCH 623/665] trac #18346: A 'cdef class' is a 'type', not a 'class' --- src/sage/graphs/digraph.py | 2 +- src/sage/graphs/generic_graph.py | 20 ++++++++++---------- src/sage/graphs/graph.py | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index f7749d256e4..6d842df21e6 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1127,7 +1127,7 @@ def to_undirected(self, implementation='c_graph', data_structure=None, Immutable graphs yield immutable graphs (:trac:`17005`):: sage: DiGraph([[1, 2]], immutable=True).to_undirected()._backend - + """ if sparse is not None: if data_structure is not None: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ee71616aead..5931195c1fe 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -950,27 +950,27 @@ def copy(self, weighted=None, implementation='c_graph', data_structure=None, Which backend ?:: sage: G.copy(data_structure="sparse")._backend - + sage: G.copy(data_structure="dense")._backend - + sage: G.copy(data_structure="static_sparse")._backend - + sage: G.copy(immutable=True)._backend - + sage: G.copy(immutable=True, sparse=True)._backend - + sage: G.copy(immutable=False, sparse=True)._backend - + sage: G.copy(immutable=False, sparse=False)._backend - + sage: Graph(implementation="networkx").copy(implementation='c_graph')._backend - + Fake immutable graphs:: sage: G._immutable = True sage: G.copy()._backend - + """ # Which data structure should be used ? if implementation != 'c_graph': @@ -14318,7 +14318,7 @@ def union(self, other): sage: g = g.copy(immutable=True) sage: (2*g)._backend - + """ if (self._directed and not other._directed) or (not self._directed and other._directed): raise TypeError('both arguments must be of the same class') diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 881dbfbd1fd..ada859d260a 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4715,7 +4715,7 @@ def to_directed(self, implementation='c_graph', data_structure=None, Immutable graphs yield immutable graphs:: sage: Graph([[1, 2]], immutable=True).to_directed()._backend - + :trac:`17005`:: From 031990b6f10254bd426c4fd63fba893ead7e81dd Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Fri, 1 May 2015 16:14:46 +0200 Subject: [PATCH 624/665] add doctest --- src/sage/graphs/graph_plot.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 03afe2cdb2b..3be7f30bace 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -894,6 +894,14 @@ def plot(self, **kwds): ... ValueError: Invalid input 'egabrag=garbage' + Make sure that no graphics primitive is clipped:: + + sage: tadpole = Graph({0:[0,1]}).plot() + sage: bbox = tadpole.get_minmax_data() + sage: for part in tadpole: + ....: part_bbox = part.get_minmax_data() + ....: assert bbox['xmin'] <= part_bbox['xmin'] <= part_bbox['xmax'] <= bbox['xmax'] + ....: assert bbox['ymin'] <= part_bbox['ymin'] <= part_bbox['ymax'] <= bbox['ymax'] """ G = Graphics() options = self._options.copy() From c6678ce267bef7b5f805e78adae57c0b1d8a8b5d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 17:27:16 +0200 Subject: [PATCH 625/665] trac #18317: Review --- src/sage/graphs/base/graph_backends.py | 20 ++++++++++---------- src/sage/graphs/digraph.py | 2 +- src/sage/graphs/graph.py | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.py b/src/sage/graphs/base/graph_backends.py index 28da660d1a2..15a71619d31 100644 --- a/src/sage/graphs/base/graph_backends.py +++ b/src/sage/graphs/base/graph_backends.py @@ -17,13 +17,13 @@ :meth:`~GenericGraphBackend.add_edges` | Add a sequence of edges to ``self``. :meth:`~GenericGraphBackend.add_vertex` | Add a labelled vertex to ``self``. :meth:`~GenericGraphBackend.add_vertices` | Add labelled vertices to ``self``. - :meth:`~GenericGraphBackend.degree` | Returns the total number of vertices incident to v. + :meth:`~GenericGraphBackend.degree` | Return the total number of vertices incident to `v`. :meth:`~GenericGraphBackend.in_degree` | Return the in-degree of `v` :meth:`~GenericGraphBackend.out_degree` | Return the out-degree of `v` :meth:`~GenericGraphBackend.del_edge` | Deletes the edge `(u,v)` with label `l`. :meth:`~GenericGraphBackend.del_vertex` | Delete a labelled vertex in ``self``. :meth:`~GenericGraphBackend.del_vertices` | Delete labelled vertices in ``self``. - :meth:`~GenericGraphBackend.get_edge_label` | Returns the edge label of `(u,v)`. + :meth:`~GenericGraphBackend.get_edge_label` | Return the edge label of `(u,v)`. :meth:`~GenericGraphBackend.has_edge` | True if ``self`` has an edge `(u,v)` with label `l`. :meth:`~GenericGraphBackend.has_vertex` | True if ``self`` has a vertex with label `v`. :meth:`~GenericGraphBackend.iterator_edges` | Iterate over the edges incident to a sequence of vertices. @@ -159,7 +159,7 @@ def add_vertices(self, vertices): raise NotImplementedError() def degree(self, v, directed): """ - Returns the total number of vertices incident to v. + Return the total number of vertices incident to `v`. INPUT: @@ -268,7 +268,7 @@ def del_vertices(self, vertices): raise NotImplementedError() def get_edge_label(self, u, v): """ - Returns the edge label of (u,v). + Return the edge label of `(u,v)`. INPUT: @@ -276,7 +276,7 @@ def get_edge_label(self, u, v): OUTPUT: - label of (u,v) + label of `(u,v)` TESTS:: @@ -929,7 +929,7 @@ def add_vertices(self, vertices): def degree(self, v, directed): """ - Returns the total number of vertices incident to v. + Return the total number of vertices incident to `v`. INPUT: @@ -954,7 +954,7 @@ def degree(self, v, directed): def in_degree(self, v): """ - Returns the in-degree of v. + Return the in-degree of `v`. INPUT: @@ -980,7 +980,7 @@ def in_degree(self, v): def out_degree(self, v): """ - Returns the out-degree of v. + Return the out-degree of `v`. INPUT: @@ -1081,14 +1081,14 @@ def del_vertices(self, vertices): def get_edge_label(self, u, v): """ - Returns the edge label of (u,v). + Return the edge label of `(u,v)`. INPUT: - ``u,v`` -- vertex labels OUTPUT: - label of (u,v) + label of `(u,v)` TESTS:: diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 43dd1ce5b1b..18e4de6491c 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -264,7 +264,7 @@ class DiGraph(GenericGraph): ``data_structure="dense"``. - ``data_structure`` -- one of the following (for more information, see - :mod:`~sage.graphs.base.overview`): + :mod:`~sage.graphs.base.overview`): * ``"dense"`` -- selects the :mod:`~sage.graphs.base.dense_graph` backend. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 4cb75896ed8..28740408371 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -693,7 +693,7 @@ class Graph(GenericGraph): ``data_structure="dense"``. - ``data_structure`` -- one of the following (for more information, see - :mod:`~sage.graphs.base.overview`) + :mod:`~sage.graphs.base.overview`) * ``"dense"`` -- selects the :mod:`~sage.graphs.base.dense_graph` backend. From 4378790c6996a3e4949737a1bf2b9bb8c4cc217d Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Fri, 1 May 2015 17:28:48 +0200 Subject: [PATCH 626/665] trac #18317: Delete(s) --- src/sage/graphs/base/graph_backends.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.py b/src/sage/graphs/base/graph_backends.py index 15a71619d31..709d43c6a2c 100644 --- a/src/sage/graphs/base/graph_backends.py +++ b/src/sage/graphs/base/graph_backends.py @@ -20,7 +20,7 @@ :meth:`~GenericGraphBackend.degree` | Return the total number of vertices incident to `v`. :meth:`~GenericGraphBackend.in_degree` | Return the in-degree of `v` :meth:`~GenericGraphBackend.out_degree` | Return the out-degree of `v` - :meth:`~GenericGraphBackend.del_edge` | Deletes the edge `(u,v)` with label `l`. + :meth:`~GenericGraphBackend.del_edge` | Delete the edge `(u,v)` with label `l`. :meth:`~GenericGraphBackend.del_vertex` | Delete a labelled vertex in ``self``. :meth:`~GenericGraphBackend.del_vertices` | Delete labelled vertices in ``self``. :meth:`~GenericGraphBackend.get_edge_label` | Return the edge label of `(u,v)`. @@ -215,7 +215,7 @@ def out_degree(self, v): raise NotImplementedError() def del_edge(self, u, v, l, directed): """ - Deletes the edge (u,v) with label l. + Delete the edge `(u,v)` with label `l`. INPUT: @@ -1006,7 +1006,7 @@ def out_degree(self, v): def del_edge(self, u, v, l, directed): """ - Deletes the edge (u,v) with label l. + Delete the edge `(u,v)` with label `l`. INPUT: From ba085b7a1d215645748b7cfd43053f03eec087d6 Mon Sep 17 00:00:00 2001 From: Sebastien Gouezel Date: Fri, 1 May 2015 18:21:45 +0200 Subject: [PATCH 627/665] #18348 link /graphs/centrality with gmp --- src/sage/graphs/centrality.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 5dfb44cdbbc..958acc16f5a 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -1,3 +1,4 @@ +# distutils: libraries = gmp r""" Centrality From aa952a9096d8507ae4c84eea3cd38d5f123d2924 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 1 May 2015 17:50:26 +0100 Subject: [PATCH 628/665] updated 4ti2 to new version 1.6.3 and to new spkg style --- build/pkgs/4ti2/SPKG.txt | 34 +++++++++++++++++++++++++++++ build/pkgs/4ti2/checksums.ini | 4 ++++ build/pkgs/4ti2/package-version.txt | 1 + build/pkgs/4ti2/spkg-install | 22 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 build/pkgs/4ti2/SPKG.txt create mode 100644 build/pkgs/4ti2/checksums.ini create mode 100644 build/pkgs/4ti2/package-version.txt create mode 100755 build/pkgs/4ti2/spkg-install diff --git a/build/pkgs/4ti2/SPKG.txt b/build/pkgs/4ti2/SPKG.txt new file mode 100644 index 00000000000..1b3f3ac3f8e --- /dev/null +++ b/build/pkgs/4ti2/SPKG.txt @@ -0,0 +1,34 @@ += 4ti2 = + +== Description == + +A software package for algebraic, geometric and combinatorial problems on linear spaces. Available at www.4ti2.de. + +== License == +4ti2 is released under a GPL v2 license. + +== SPKG Maintainers == + +Marshall Hampton +Dima Pasechnik + +== Upstream Contact == + +Raymond Hemmecke, TU Munich, Germany +Matthias Köppe, UC Davis, CA, USA + +== Dependencies == + +GLPK, GMP. + +=== 4ti2-1.6.2 (Dima Pasechnik, Jul 4, 2014) === + * update to 4ti2 version 1.6.2 + +=== 4ti2-1.6 (Dima Pasechnik, Sept 7, 2013) === + * update to 4ti2 version 1.6 + * hg: added stuff to track + * updated upstream contacts + +=== 4ti2.p0 (Marshall Hampton, July 31th, 2009) === + * Created a first attempt. + diff --git a/build/pkgs/4ti2/checksums.ini b/build/pkgs/4ti2/checksums.ini new file mode 100644 index 00000000000..cf044c43743 --- /dev/null +++ b/build/pkgs/4ti2/checksums.ini @@ -0,0 +1,4 @@ +tarball=4ti2-VERSION.tar.gz +sha1=aa0da036c061d39092a6c8b84ccc279544fd510f +md5=32e2a4320b068ce3e08a7521087f4869 +cksum=1513346505 diff --git a/build/pkgs/4ti2/package-version.txt b/build/pkgs/4ti2/package-version.txt new file mode 100644 index 00000000000..266146b87cb --- /dev/null +++ b/build/pkgs/4ti2/package-version.txt @@ -0,0 +1 @@ +1.6.3 diff --git a/build/pkgs/4ti2/spkg-install b/build/pkgs/4ti2/spkg-install new file mode 100755 index 00000000000..10d9256fec2 --- /dev/null +++ b/build/pkgs/4ti2/spkg-install @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +cd src/ + +if [ "$SAGE_LOCAL" = "" ]; then + echo "SAGE_LOCAL undefined ... exiting"; + echo "Maybe run 'sage -sh'?" + exit 1 +fi + +CFLAGS="-I $SAGE_LOCAL/include -L$SAGE_LOCAL/lib $CFLAGS" +export CFLAGS +./configure --prefix=$SAGE_LOCAL --with-gmp=$SAGE_LOCAL --with-glpk=$SAGE_LOCAL --enable-shared=yes --enable-static=no + +$MAKE +$MAKE install + +if [ $? -ne 0 ]; then + echo "Error building 4ti2" + exit 1 +fi + From 9c4bb3194b9271b00458dd76c37480b2bd86b41c Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 1 May 2015 17:52:18 +0100 Subject: [PATCH 629/665] updated SPKG.txt --- build/pkgs/4ti2/SPKG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/pkgs/4ti2/SPKG.txt b/build/pkgs/4ti2/SPKG.txt index 1b3f3ac3f8e..781eacaf0de 100644 --- a/build/pkgs/4ti2/SPKG.txt +++ b/build/pkgs/4ti2/SPKG.txt @@ -21,6 +21,9 @@ Matthias Köppe, UC Davis, CA, USA GLPK, GMP. +=== 4ti2-1.6.3 (Dima Pasechnik, May 1, 2015) === + * update to 4ti2 version 1.6.3 and to new spkg style + === 4ti2-1.6.2 (Dima Pasechnik, Jul 4, 2014) === * update to 4ti2 version 1.6.2 From c0b60e137ecccccb472eb6d4c9bc3f43be1294d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 1 May 2015 21:12:39 +0200 Subject: [PATCH 630/665] trac #18324 a few doc details in 4ti2 interface --- src/sage/interfaces/four_ti_2.py | 47 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 83133394706..c6e3cdb1dd6 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -6,6 +6,8 @@ You must have the 4ti2 Sage package installed on your computer for this interface to work. +Use ``sage -i 4ti2`` to install the package. + AUTHORS: - Mike Hansen (2009): Initial version. @@ -36,22 +38,22 @@ from sage.rings.integer_ring import ZZ import os + class FourTi2(object): r""" This object defines an interface to the program 4ti2. Each command 4ti2 has is exposed as one method. """ - def __init__(self, directory=None): r""" Initialize this object. INPUT: - - ``directory`` - 4ti2 only deals with files, and this is the - directory that Sage will write input files to and run 4ti2 - in. Use an appropriate temporary directory if the value is - ``None``. + - ``directory`` -- 4ti2 only deals with files, and this is the + directory that Sage will write input files to and run 4ti2 + in. Use an appropriate temporary directory if the value is + ``None``. EXAMPLES:: @@ -98,7 +100,7 @@ def temp_project(self): """ n = 0 while True: - project = "project_%s"%n + project = "project_%s" % n touch_file = os.path.join(self.directory(),project) + '.touch' if not os.path.exists(touch_file): break @@ -114,9 +116,9 @@ def write_matrix(self, mat, filename): INPUT: - - ``mat`` - A matrix of integers or something that can be - converted to that. - - ``filename`` - A file name not including a path. + - ``mat`` -- A matrix of integers or something that can be + converted to that. + - ``filename`` -- A file name not including a path. EXAMPLES:: @@ -139,8 +141,8 @@ def write_single_row(self, row, filename): INPUT: - - ``row`` - A list of integers. - - ``filename`` - A file name not including a path. + - ``row`` -- A list of integers. + - ``filename`` -- A file name not including a path. EXAMPLES:: @@ -158,11 +160,11 @@ def write_array(self, array, nrows, ncols, filename): INPUT: - - ``array`` - A matrix of integers. Can be represented as a list - of lists. - - ``nrows`` - The number of rows in ``array``. - - ``ncols`` - The number of columns in ``array``. - - ``file`` - A file name not including a path. + - ``array`` -- A matrix of integers. Can be represented as a list + of lists. + - ``nrows`` -- The number of rows in ``array``. + - ``ncols`` -- The number of columns in ``array``. + - ``file`` -- A file name not including a path. EXAMPLES:: @@ -183,9 +185,10 @@ def read_matrix(self, filename): INPUT: - - ``filename`` - The name of the file to read from. + - ``filename`` -- The name of the file to read from. OUTPUT: + The data from the file as a matrix over `\ZZ`. EXAMPLES:: @@ -228,7 +231,7 @@ def _process_input(self, kwds): INPUT: - - kwds - A dict controlling what data is written to what files. + - kwds -- A dict controlling what data is written to what files. OUTPUT: @@ -275,9 +278,9 @@ def call(self, command, project, verbose=True): INPUT: - - command - The 4ti2 program to run. - - project - The file name of the project to run on. - - verbose - Display the output of 4ti2 if ``True``. + - command -- The 4ti2 program to run. + - project -- The file name of the project to run on. + - verbose -- Display the output of 4ti2 if ``True``. EXAMPLES:: @@ -290,7 +293,7 @@ def call(self, command, project, verbose=True): """ import subprocess - cmd = '%s %s'%(command, project) + cmd = '%s %s' % (command, project) if verbose is False: cmd += " > /dev/null 2> /dev/null" subprocess.call(cmd, shell=True, cwd=self.directory()) From c6879c8c829adc192ac2c400548baa1c3bf6eb15 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Fri, 1 May 2015 18:31:39 -0600 Subject: [PATCH 631/665] Remove EMBEDDED_MODE from interactive_simplex_method.py --- src/sage/numerical/interactive_simplex_method.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 137c2bd6914..4a7db2b3524 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -175,7 +175,7 @@ #***************************************************************************** -import operator, re, sys +import operator, re from copy import copy @@ -192,7 +192,6 @@ latex, randint, random) -from sage.misc.latex import EMBEDDED_MODE from sage.misc.misc import get_main_globals from sage.modules.all import random_vector, vector from sage.plot.all import Graphics, arrow, line, point, rainbow, text @@ -206,7 +205,7 @@ # LaTeX. We use our own variable as it may be convenient to override it. # Hopefully, some day there will be no need in it at all and only "if" parts # will have to be left. -generate_real_LaTeX = not EMBEDDED_MODE +generate_real_LaTeX = False def _assemble_arrayl(lines, stretch=None): r""" From 11ce9814729ea25384715b293ea3711f0354b6a2 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Sat, 2 May 2015 08:32:50 +0200 Subject: [PATCH 632/665] More integration doctest fixes --- src/sage/calculus/calculus.py | 6 +++--- src/sage/libs/pari/pari_instance.pyx | 3 ++- src/sage/tests/french_book/integration_doctest.py | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index e3fcbf1e2fc..a9bcc7d2940 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -736,11 +736,11 @@ def nintegral(ex, x, a, b, to high precision:: sage: gp.eval('intnum(x=17,42,exp(-x^2)*log(x))') - '2.565728500561051482917356396 E-127' # 32-bit - '2.5657285005610514829173563961304785900 E-127' # 64-bit + '2.565728500561051474934096410 E-127' # 32-bit + '2.5657285005610514829176211363206621657 E-127' # 64-bit sage: old_prec = gp.set_real_precision(50) sage: gp.eval('intnum(x=17,42,exp(-x^2)*log(x))') - '2.5657285005610514829173563961304785900147709554020 E-127' + '2.5657285005610514829173563961304957417746108003917 E-127' sage: gp.set_real_precision(old_prec) 57 diff --git a/src/sage/libs/pari/pari_instance.pyx b/src/sage/libs/pari/pari_instance.pyx index 16e2ca1699f..22a06c72b5f 100644 --- a/src/sage/libs/pari/pari_instance.pyx +++ b/src/sage/libs/pari/pari_instance.pyx @@ -33,7 +33,8 @@ EXAMPLES:: sage: pari('5! + 10/x') (120*x + 10)/x sage: pari('intnum(x=0,13,sin(x)+sin(x^2) + x)') - 84.1818153922297 + 83.8179442684285 # 32-bit + 84.1818153922297 # 64-bit sage: f = pari('x^3-1') sage: v = f.factor(); v [x - 1, 1; x^2 + x + 1, 1] diff --git a/src/sage/tests/french_book/integration_doctest.py b/src/sage/tests/french_book/integration_doctest.py index 14b6bb749e5..83a1863bba6 100644 --- a/src/sage/tests/french_book/integration_doctest.py +++ b/src/sage/tests/french_book/integration_doctest.py @@ -78,8 +78,8 @@ Sage example in ./integration.tex, line 465:: - sage: gp('intnum(x=17, 42, exp(-x^2)*log(x))') # rel tol 8e-29 - 2.5657285005610514829173563961304785900 E-127 + sage: gp('intnum(x=17, 42, exp(-x^2)*log(x))') # rel tol 1e-17 + 2.5657285005610514829176211363206621657 E-127 Sage example in ./integration.tex, line 474:: From 661c008e33f1384e9875bd500c148943988d580b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sat, 2 May 2015 08:52:10 +0200 Subject: [PATCH 633/665] 16659: orthogonal_idempotents_central_mod_rad -> ...mod_radical + small doc fix --- .../finite_dimensional_algebras_with_basis.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 3fae7dfdbb3..e126c654230 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -444,7 +444,7 @@ def principal_ideal(self, a, side='left'): for b in self.basis()]) @cached_method - def orthogonal_idempotents_central_mod_rad(self): + def orthogonal_idempotents_central_mod_radical(self): r""" Return a family of orthogonal idempotents of ``self`` that project on the central orthogonal idempotents of the semisimple quotient. @@ -481,7 +481,7 @@ def orthogonal_idempotents_central_mod_rad(self): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents_central_mod_rad() + sage: A.orthogonal_idempotents_central_mod_radical() [x, y] :: @@ -489,7 +489,7 @@ def orthogonal_idempotents_central_mod_rad(self): sage: Z12 = Monoids().Finite().example(); Z12 An example of a finite multiplicative monoid: the integers modulo 12 sage: A = Z12.algebra(QQ) - sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: idempotents = A.orthogonal_idempotents_central_mod_radical() sage: sorted(idempotents, key=str) [-1/2*B[3] + 1/2*B[9], -1/2*B[8] + 1/2*B[4], @@ -517,7 +517,7 @@ def orthogonal_idempotents_central_mod_rad(self): sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) - sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: idempotents = A.orthogonal_idempotents_central_mod_radical() sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True """ @@ -595,7 +595,7 @@ def cartan_invariants_matrix(self): Let `A` be this finite dimensional algebra and `(S_i)_{i\in I}` be representatives of the right simple modules of `A`. Note that their adjoints `S_i^*` are - representatives of the right simple modules. + representatives of the left simple modules. Let `(P^L_i)_{i\in I}` and `(P^R_i)_{i\in I}` be respectively representatives of the corresponding @@ -704,7 +704,7 @@ def cartan_invariants_matrix(self): dim_simples = [sqrt(A_quo.principal_ideal(e).dimension()) for e in idempotents_quo] # Orthogonal idempotents - idempotents = self.orthogonal_idempotents_central_mod_rad() + idempotents = self.orthogonal_idempotents_central_mod_radical() def C(i,j): summand = self.peirce_summand(idempotents[i], idempotents[j]) return summand.dimension() / (dim_simples[i]*dim_simples[j]) @@ -759,11 +759,11 @@ def isotypic_projective_modules(self, side='left'): .. SEEALSO:: - - :meth:`orthogonal_idempotents_central_mod_rad` + - :meth:`orthogonal_idempotents_central_mod_radical` - :meth:`peirce_decomposition` """ return [self.principal_ideal(e, side) for e in - self.orthogonal_idempotents_central_mod_rad()] + self.orthogonal_idempotents_central_mod_radical()] @cached_method def peirce_summand(self, ei, ej): @@ -786,7 +786,7 @@ def peirce_summand(self, ei, ej): EXAMPLES:: sage: A = Algebras(QQ).FiniteDimensional().WithBasis().example() - sage: idemp = A.orthogonal_idempotents_central_mod_rad() + sage: idemp = A.orthogonal_idempotents_central_mod_radical() sage: A.peirce_summand(idemp[0], idemp[1]) Free module generated by {0, 1} over Rational Field sage: A.peirce_summand(idemp[1], idemp[0]) @@ -832,7 +832,7 @@ def peirce_decomposition(self, idempotents=None, check=True): - ``idempotents`` -- a list of orthogonal idempotents `(e_i)_{i=0,\ldots,n}` of the algebra that sum to `1` (default: the idempotents returned by - :meth:`orthogonal_idempotents_central_mod_rad`) + :meth:`orthogonal_idempotents_central_mod_radical`) - ``check`` -- (default:True) whether to check that the idempotents are indeed orthogonal @@ -844,7 +844,7 @@ def peirce_decomposition(self, idempotents=None, check=True): .. SEEALSO:: - - :meth:`orthogonal_idempotents_central_mod_rad` + - :meth:`orthogonal_idempotents_central_mod_radical` - :meth:`cartan_invariants_matrix` EXAMPLES:: @@ -853,7 +853,7 @@ def peirce_decomposition(self, idempotents=None, check=True): An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field - sage: A.orthogonal_idempotents_central_mod_rad() + sage: A.orthogonal_idempotents_central_mod_radical() [x, y] sage: decomposition = A.peirce_decomposition(); decomposition [[Free module generated by {0} over Rational Field, @@ -888,7 +888,7 @@ def peirce_decomposition(self, idempotents=None, check=True): [1, 3, 2, 3, 1] """ if idempotents is None: - idempotents = self.orthogonal_idempotents_central_mod_rad() + idempotents = self.orthogonal_idempotents_central_mod_radical() if check: if not self.is_identity_decomposition_into_orthogonal_idempotents(idempotents): raise ValueError("Not a decomposition of the identity into orthogonal idempotents") @@ -935,7 +935,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): sage: from sage.monoids.hecke_monoid import HeckeMonoid sage: A = HeckeMonoid(SymmetricGroup(4)).algebra(QQ) - sage: idempotents = A.orthogonal_idempotents_central_mod_rad() + sage: idempotents = A.orthogonal_idempotents_central_mod_radical() sage: A.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True From 1fc0d19155e96132e5c5d14888594917a2038624 Mon Sep 17 00:00:00 2001 From: Dmitrii Pasechnik Date: Sat, 2 May 2015 09:55:40 +0100 Subject: [PATCH 634/665] typo fixes as of https://groups.google.com/d/msg/sage-support/pehl9pIVoJ0/Z19SgNHOlDoJ --- src/bin/sage | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/sage b/src/bin/sage index a410bf4fe8d..6c1b0ab7d85 100755 --- a/src/bin/sage +++ b/src/bin/sage @@ -43,7 +43,7 @@ usage() { echo " --help - show all testing options" echo " -upgrade [version] -- download, build and install the given version. Here," echo " 'version' is a git branch or tag name. Useful values" - echo " are 'master' (the currend development version, this" + echo " are 'master' (the current development version, this" echo " is the default) or a version number like '5.13'." echo " -v, -version -- display Sage version information" exit 0 @@ -136,7 +136,7 @@ usage_advanced() { #echo " -update-build -- build and install all downloaded non-optional Sage packages" echo " -upgrade [version] -- download, build and install the given version. Here," echo " 'version' is a git branch or tag name. Useful values" - echo " are 'master' (the currend development version, this" + echo " are 'master' (the current development version, this" echo " is the default) or a version number like '5.13'." echo From a0ac11b26f4ded7bbcbef5bb6a1f81ae8ed354f6 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 2 May 2015 14:58:43 +0200 Subject: [PATCH 635/665] #14982 Map.domains(): improve documentation --- src/sage/categories/map.pyx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index e420629f6bc..499b1b22486 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -593,10 +593,14 @@ cdef class Map(Element): def domains(self): """ - Yield the domain of self. In general, iterate over the domains of - the factors of a composite map. + Iterate over the domains of the factors of a (composite) map. + + This default implementation simply yields the domain of this map. + + .. SEEALSO:: :meth:`FormalCompositeMap.domains` EXAMPLES:: + sage: list(QQ.coerce_map_from(ZZ).domains()) [Integer Ring] """ @@ -1917,9 +1921,13 @@ cdef class FormalCompositeMap(Map): def domains(self): """ - Iterate over the domains of the factors of self. + Iterate over the domains of the factors of this map. - EXAMPLES::: + (This is useful in particular to check for loops in coercion maps.) + + .. SEEALSO:: :meth:`Map.domains` + + EXAMPLES:: sage: f = QQ.coerce_map_from(ZZ) sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) From 60f544f3969366c96b4874cf36ff556dcbb50f10 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 2 May 2015 07:03:28 -0700 Subject: [PATCH 636/665] Adding some examples and changing the repr of SchurAlgebra elements. --- src/sage/algebras/schur_algebra.py | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 8c1580c4d73..dfb3030ddec 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -247,6 +247,7 @@ def __init__(self, R, n, r): CombinatorialFreeModule.__init__(self, R, schur_representative_indices(n, r), + prefix='S', bracket=False, category=AlgebrasWithBasis(R)) def _repr_(self): @@ -270,7 +271,7 @@ def one(self): sage: S = SchurAlgebra(ZZ, 2, 2) sage: e = S.one(); e - B[((1, 1), (1, 1))] + B[((1, 2), (1, 2))] + B[((2, 2), (2, 2))] + S((1, 1), (1, 1)) + S((1, 2), (1, 2)) + S((2, 2), (2, 2)) sage: x = S.an_element() sage: x * e == x @@ -312,14 +313,14 @@ def product_on_basis(self, e_ij, e_kl): sage: ww = B[((1, 2, 2), (1, 2, 2))] sage: x = B[((1, 2, 2), (1, 1, 2))] sage: ww * x - B[((1, 2, 2), (1, 1, 2))] + S((1, 2, 2), (1, 1, 2)) An arbitrary product, on the other hand, may have multiplicities:: sage: x = B[((1, 1, 1), (1, 1, 2))] sage: y = B[((1, 1, 2), (1, 2, 2))] sage: x * y - 2*B[((1, 1, 1), (1, 2, 2))] + 2*S((1, 1, 1), (1, 2, 2)) """ j = e_ij[1] @@ -392,9 +393,32 @@ class SchurTensorModule(CombinatorialFreeModule_Tensor): EXAMPLES:: - sage: SchurTensorModule(QQ, 2, 3) + sage: T = SchurTensorModule(QQ, 2, 3); T The 3-fold tensor product of a free module of dimension 2 - over Rational Field + over Rational Field + sage: A = SchurAlgebra(QQ, 2, 3) + sage: P = Permutations(3) + sage: t = T.an_element(); t + 2*B[1] # B[1] # B[1] + 2*B[1] # B[1] # B[2] + 3*B[1] # B[2] # B[1] + sage: a = A.an_element(); a + 2*S((1, 1, 1), (1, 1, 1)) + 2*S((1, 1, 1), (1, 1, 2)) + + 3*S((1, 1, 1), (1, 2, 2)) + sage: p = P.an_element(); p + [3, 1, 2] + sage: y = a * t; y + 14*B[1] # B[1] # B[1] + sage: y * p + 14*B[1] # B[1] # B[1] + sage: z = t * p; z + 2*B[1] # B[1] # B[1] + 3*B[1] # B[1] # B[2] + 2*B[2] # B[1] # B[1] + sage: a * z + 14*B[1] # B[1] # B[1] + + We check the commuting action property:: + + sage: all( (bA * bT) * p == bA * (bT * p) + ....: for bT in T.basis() for bA in A.basis() for p in P) + True """ def __init__(self, R, n, r): """ From a3ac4598f72ca7a9d67bfa59eb9f854a92ecfa74 Mon Sep 17 00:00:00 2001 From: Buck Evan Date: Sat, 2 May 2015 07:44:08 -0700 Subject: [PATCH 637/665] strip gcc bootstrap in osx: #18156 --- build/pkgs/gcc/spkg-install | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/pkgs/gcc/spkg-install b/build/pkgs/gcc/spkg-install index 54ec8a5914a..a93411334ad 100755 --- a/build/pkgs/gcc/spkg-install +++ b/build/pkgs/gcc/spkg-install @@ -81,9 +81,15 @@ if { uname -sr | grep 'Darwin 14\.' ;} &>/dev/null; then fi fi -# On OSX: isl/cloog libraries are almost certainly from Homebrew and won't work +# On OSX: if [ "$UNAME" = "Darwin" ]; then + # isl/cloog libraries are almost certainly from Homebrew and won't work GCC_CONFIGURE="--without-isl --without-cloog $GCC_CONFIGURE" + + # Use 'bootstrap-debug' build configuration to force stripping of object + # files prior to comparison during bootstrap (broken by Xcode 6.3). + # See #18156 + GCC_CONFIGURE="--with-build-config=bootstrap-debug $GCC_CONFIGURE" fi # Let GCC build on Raspberry Pi using hard floats. From c626eec1f23ab4f1529efe1efa3f738b30589b74 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sat, 2 May 2015 21:10:44 +0200 Subject: [PATCH 638/665] trac #18346: Without useless 'objects' --- src/sage/graphs/base/c_graph.pxd | 4 ++-- src/sage/graphs/base/c_graph.pyx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pxd b/src/sage/graphs/base/c_graph.pxd index 39fa6070449..139dab556ef 100644 --- a/src/sage/graphs/base/c_graph.pxd +++ b/src/sage/graphs/base/c_graph.pxd @@ -41,8 +41,8 @@ cdef class CGraph: cdef int add_vertex_unsafe(self, int) except -1 cdef class CGraphBackend(GenericGraphBackend): - cdef int get_vertex(self, object u) except ? -2 - cdef object vertex_label(self, int u_int) + cdef int get_vertex(self, u) except ? -2 + cdef vertex_label(self, int u_int) cdef int check_labelled_vertex(self, object u, bint reverse) except ? -1 cdef CGraph _cg cdef CGraph _cg_rev diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 3fb4bdd3332..d8db449173e 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1153,7 +1153,7 @@ cdef class CGraphBackend(GenericGraphBackend): -- backend for dense graphs. """ - cdef int get_vertex(self, object u) except ? -2: + cdef int get_vertex(self, u) except ? -2: """ Returns an int representing the arbitrary hashable vertex u (whether or not u is actually in the graph), or -1 if a new association must be made for u @@ -1207,7 +1207,7 @@ cdef class CGraphBackend(GenericGraphBackend): return -1 return u_int - cdef object vertex_label(self, int u_int): + cdef vertex_label(self, int u_int): """ Returns the object represented by u_int, or None if this does not represent a vertex. From ea552de571a529ac3f10f132f1beec50bf14d9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sun, 3 May 2015 09:51:11 +0200 Subject: [PATCH 639/665] 16659: split Algebras.Semisimple.FiniteDimensional.WithBasis in its own file: first step: copying the file --- ...ensional_semisimple_algebras_with_basis.py | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py new file mode 100644 index 00000000000..79592f5266f --- /dev/null +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -0,0 +1,313 @@ +r""" +Semisimple Algebras +""" +#***************************************************************************** +# Copyright (C) 2011-2015 Nicolas M. Thiery +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.bindable_class import BoundClass +from category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.misc.cachefunc import cached_method +from algebras import Algebras + + +class SemisimpleAlgebras(Category_over_base_ring): + """ + The category of semisimple algebras over a given base ring. + + EXAMPLES:: + + sage: from sage.categories.semisimple_algebras import SemisimpleAlgebras + sage: C = SemisimpleAlgebras(QQ); C + Category of semisimple algebras over Rational Field + + This category is best constructed as:: + + sage: D = Algebras(QQ).Semisimple(); D + Category of semisimple algebras over Rational Field + sage: D is C + True + + sage: C.super_categories() + [Category of algebras over Rational Field] + + Typically, finite group algebras are semisimple:: + + sage: DihedralGroup(5).algebra(QQ) in SemisimpleAlgebras + True + + Unless the characteristic of the field divides the order of the group:: + + sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras + False + + sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras + True + + .. SEEALSO:: ``_ + + TESTS:: + + sage: TestSuite(C).run() + """ + @staticmethod + def __classget__(cls, base_category, base_category_class): + """ + Implement the shorthand ``Algebras(K).Semisimple()`` for ``SemisimpleAlgebras(K)``. + + This magic mimics the syntax of axioms for a smooth transition + if ``Semisimple`` becomes one. + + EXAMPLES:: + + sage: Algebras(QQ).Semisimple() + Category of semisimple algebras over Rational Field + sage: Algebras.Semisimple + + """ + if base_category is None: + return cls + return BoundClass(cls, base_category.base_ring()) + + @cached_method + def super_categories(self): + """ + EXAMPLES:: + + sage: Algebras(QQ).Semisimple().super_categories() + [Category of algebras over Rational Field] + """ + R = self.base_ring() + return [Algebras(R)] + + class ParentMethods: + + def radical_basis(self, **keywords): + r""" + Return a basis of the Jacobson radical of this algebra. + + - ``keywords`` -- for compatibility; ignored. + + OUTPUT: the empty list since this algebra is semisimple. + + EXAMPLES:: + + sage: A = SymmetricGroup(4).algebra(QQ) + sage: A.radical_basis() + [] + + TESTS:: + + sage: A.radical_basis.__module__ + 'sage.categories.finite_dimensional_algebras_with_basis' + """ + return [] + + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + + class WithBasis(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def central_orthogonal_idempotents(self): + r""" + Return a maximal list of central orthogonal + idempotents of ``self``. + + *Central orthogonal idempotents* of an algebra `A` + are idempotents `(e_1, \dots, e_n)` in the center + of `A` such that `e_i e_j = 0` whenever `i \neq j`. + + With the maximality condition, they sum up to `1` + and are uniquely determined (up to order). + + INPUT: + + - ``self`` -- a semisimple algebra. + + EXAMPLES: + + For the algebra of the symmetric group `S_3`, we + recover the sum and alternating sum of all + permutations, together with a third idempotent:: + + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: idempotents = A3.central_orthogonal_idempotents() + sage: idempotents + [1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + 2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), + 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] + sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + True + + For the semisimple quotient of a quiver algebra, + we recover the vertices of the quiver:: + + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver (containing + the arrows a:x->y and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: Aquo.central_orthogonal_idempotents() + [B['x'], B['y']] + """ + return [x.lift() + for x in self.center().central_orthogonal_idempotents()] + + + class Commutative(CategoryWithAxiom_over_base_ring): + + class ParentMethods: + + @cached_method + def _orthogonal_decomposition(self, generators=None): + r""" + Return a maximal list of orthogonal quasi-idempotents of + this finite dimensional semisimple commutative algebra. + + INPUT: + + - ``generators`` -- a list of generators of + ``self`` (default: the basis of ``self``) + + OUTPUT: + + A list of quasi-idempotent elements of ``self``. + + Each quasi-idempotent `e` spans a one + dimensional (non unital) subalgebra of + ``self``, and cannot be decomposed as a sum + `e=e_1+e_2` of quasi-idempotents elements. + All together, they form a basis of ``self``. + + Up to the order and scalar factors, the result + is unique. In particular it does not depend on + the provided generators which are only used + for improved efficiency. + + ALGORITHM: + + Thanks to Schur's Lemma, a commutative + semisimple algebra `A` is a direct sum of + dimension 1 subalgebras. The algorithm is + recursive and proceeds as follows: + + 0. If `A` is of dimension 1, return a non zero + element. + + 1. Otherwise: find one of the generators such + that the morphism `x \mapsto ax` has at + least two (right) eigenspaces. + + 2. Decompose both eigenspaces recursively. + + EXAMPLES: + + We compute an orthogonal decomposition of the + center of the algebra of the symmetric group + `S_4`:: + + sage: Z4 = SymmetricGroup(4).algebra(QQ).center() + sage: Z4._orthogonal_decomposition() + [B[0] + B[1] + B[2] + B[3] + B[4], + B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], + B[0] + B[2] - 1/2*B[3], + B[0] - 1/3*B[1] - 1/3*B[2] + 1/3*B[4], + B[0] - B[1] + B[2] + B[3] - B[4]] + + .. TODO:: + + Improve speed by using matrix operations + only, or even better delegating to a + multivariate polynomial solver. + """ + if self.dimension() == 1: + return self.basis().list() + + category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() + + if generators is None: + generators = self.basis().list() + + # Searching for a good generator ... + for gen in generators: + # Computing the eigenspaces of the + # linear map x -> gen*x + phi = self.module_morphism( + on_basis=lambda i: + gen*self.term(i), + codomain=self) + eigenspaces = phi.matrix().eigenspaces_right() + + if len(eigenspaces) >= 2: + # Gotcha! Let's split the algebra according to the eigenspaces + subalgebras = [ + self.submodule(map(self.from_vector, eigenspace.basis()), + category=category) + for eigenvalue, eigenspace in eigenspaces] + + # Decompose recursively each eigenspace + return [idempotent.lift() + for subalgebra in subalgebras + for idempotent in subalgebra._orthogonal_decomposition()] + # TODO: Should this be an assertion check? + raise Exception("Unable to fully decompose %s!"%self) + + @cached_method + def central_orthogonal_idempotents(self): + r""" + Return the central orthogonal idempotents of + this semisimple commutative algebra. + + Those idempotents form a maximal decomposition + of the identity into primitive orthogonal + idempotents. + + OUTPUT: + + A list of orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: A4 = SymmetricGroup(4).algebra(QQ) + sage: Z4 = A4.center() + sage: idempotents = Z4.central_orthogonal_idempotents() + sage: idempotents + [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], + 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], + 1/6*B[0] + 1/6*B[2] - 1/12*B[3], + 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], + 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] + + Lifting those idempotents from the center, we + recognize among them the sum and alternating + sum of all permutations:: + + sage: [e.lift() for e in idempotents] + [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + + 1/24*(1,3,4,2) + 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + + 1/24*(1,3,2,4) + 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + + 1/24*(1,4) + 1/24*(1,4,2,3) + 1/24*(1,4)(2,3), + ..., + 1/24*() - 1/24*(3,4) - 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + - 1/24*(2,4) - 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + - 1/24*(1,2,3,4) - 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + - 1/24*(1,3,4,2) - 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + - 1/24*(1,3,2,4) - 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + - 1/24*(1,4) - 1/24*(1,4,2,3) + 1/24*(1,4)(2,3)] + + We check that they indeed form a decomposition + of the identity of `Z_4` into orthogonal idempotents:: + + sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + True + """ + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in self._orthogonal_decomposition()] From ff577f3fa9cfdd5246c5e57f4427a1888b2654ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Sun, 3 May 2015 10:24:26 +0200 Subject: [PATCH 640/665] 16659: split Algebras.Semisimple.FiniteDimensional.WithBasis in its own file: actual work --- src/doc/en/reference/categories/index.rst | 1 + ...ensional_semisimple_algebras_with_basis.py | 450 ++++++++---------- src/sage/categories/semisimple_algebras.py | 207 +------- 3 files changed, 192 insertions(+), 466 deletions(-) diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index 1d920a61767..16bf2c3766a 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -87,6 +87,7 @@ Categories sage/categories/finite_dimensional_coalgebras_with_basis sage/categories/finite_dimensional_hopf_algebras_with_basis sage/categories/finite_dimensional_modules_with_basis + sage/categories/finite_dimensional_semisimple_algebras_with_basis sage/categories/finite_enumerated_sets sage/categories/finite_fields sage/categories/finite_groups diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py index 79592f5266f..d182f88ed22 100644 --- a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -1,313 +1,239 @@ r""" -Semisimple Algebras +Finite dimensional semisimple algebras with basis """ #***************************************************************************** # Copyright (C) 2011-2015 Nicolas M. Thiery +# 2014-2015 Aladin Virmaux # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.bindable_class import BoundClass -from category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.misc.cachefunc import cached_method from algebras import Algebras +from semisimple_algebras import SemisimpleAlgebras - -class SemisimpleAlgebras(Category_over_base_ring): +class FiniteDimensionalSemisimpleAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ - The category of semisimple algebras over a given base ring. + The category of finite dimensional semisimple algebras with a distinguished basis EXAMPLES:: - sage: from sage.categories.semisimple_algebras import SemisimpleAlgebras - sage: C = SemisimpleAlgebras(QQ); C - Category of semisimple algebras over Rational Field + sage: from sage.categories.finite_dimensional_semisimple_algebras_with_basis import FiniteDimensionalSemisimpleAlgebrasWithBasis + sage: C = FiniteDimensionalSemisimpleAlgebrasWithBasis(QQ); C + Category of finite dimensional semisimple algebras with basis over Rational Field This category is best constructed as:: - sage: D = Algebras(QQ).Semisimple(); D - Category of semisimple algebras over Rational Field + sage: D = Algebras(QQ).Semisimple().FiniteDimensional().WithBasis(); D + Category of finite dimensional semisimple algebras with basis over Rational Field sage: D is C True - sage: C.super_categories() - [Category of algebras over Rational Field] - - Typically, finite group algebras are semisimple:: - - sage: DihedralGroup(5).algebra(QQ) in SemisimpleAlgebras - True - - Unless the characteristic of the field divides the order of the group:: - - sage: DihedralGroup(5).algebra(IntegerModRing(5)) in SemisimpleAlgebras - False - - sage: DihedralGroup(5).algebra(IntegerModRing(7)) in SemisimpleAlgebras - True - - .. SEEALSO:: ``_ - TESTS:: sage: TestSuite(C).run() """ - @staticmethod - def __classget__(cls, base_category, base_category_class): - """ - Implement the shorthand ``Algebras(K).Semisimple()`` for ``SemisimpleAlgebras(K)``. - - This magic mimics the syntax of axioms for a smooth transition - if ``Semisimple`` becomes one. - - EXAMPLES:: - - sage: Algebras(QQ).Semisimple() - Category of semisimple algebras over Rational Field - sage: Algebras.Semisimple - - """ - if base_category is None: - return cls - return BoundClass(cls, base_category.base_ring()) - - @cached_method - def super_categories(self): - """ - EXAMPLES:: - - sage: Algebras(QQ).Semisimple().super_categories() - [Category of algebras over Rational Field] - """ - R = self.base_ring() - return [Algebras(R)] + _base_category_class_and_axiom = (SemisimpleAlgebras.FiniteDimensional, "WithBasis") class ParentMethods: - def radical_basis(self, **keywords): + @cached_method + def central_orthogonal_idempotents(self): r""" - Return a basis of the Jacobson radical of this algebra. - - - ``keywords`` -- for compatibility; ignored. + Return a maximal list of central orthogonal + idempotents of ``self``. - OUTPUT: the empty list since this algebra is semisimple. + *Central orthogonal idempotents* of an algebra `A` + are idempotents `(e_1, \dots, e_n)` in the center + of `A` such that `e_i e_j = 0` whenever `i \neq j`. - EXAMPLES:: + With the maximality condition, they sum up to `1` + and are uniquely determined (up to order). - sage: A = SymmetricGroup(4).algebra(QQ) - sage: A.radical_basis() - [] + INPUT: - TESTS:: + - ``self`` -- a semisimple algebra. - sage: A.radical_basis.__module__ - 'sage.categories.finite_dimensional_algebras_with_basis' - """ - return [] + EXAMPLES: - class FiniteDimensional(CategoryWithAxiom_over_base_ring): + For the algebra of the symmetric group `S_3`, we + recover the sum and alternating sum of all + permutations, together with a third idempotent:: - class WithBasis(CategoryWithAxiom_over_base_ring): + sage: A3 = SymmetricGroup(3).algebra(QQ) + sage: idempotents = A3.central_orthogonal_idempotents() + sage: idempotents + [1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), + 2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), + 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] + sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + True - class ParentMethods: - - @cached_method - def central_orthogonal_idempotents(self): - r""" - Return a maximal list of central orthogonal - idempotents of ``self``. - - *Central orthogonal idempotents* of an algebra `A` - are idempotents `(e_1, \dots, e_n)` in the center - of `A` such that `e_i e_j = 0` whenever `i \neq j`. - - With the maximality condition, they sum up to `1` - and are uniquely determined (up to order). - - INPUT: - - - ``self`` -- a semisimple algebra. - - EXAMPLES: - - For the algebra of the symmetric group `S_3`, we - recover the sum and alternating sum of all - permutations, together with a third idempotent:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: idempotents = A3.central_orthogonal_idempotents() - sage: idempotents - [1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), - 2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), - 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] - sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) - True - - For the semisimple quotient of a quiver algebra, - we recover the vertices of the quiver:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: - the path algebra of the Kronecker quiver (containing - the arrows a:x->y and b:x->y) over Rational Field - sage: Aquo = A.semisimple_quotient() - sage: Aquo.central_orthogonal_idempotents() - [B['x'], B['y']] - """ - return [x.lift() - for x in self.center().central_orthogonal_idempotents()] + For the semisimple quotient of a quiver algebra, + we recover the vertices of the quiver:: + sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A + An example of a finite dimensional algebra with basis: + the path algebra of the Kronecker quiver (containing + the arrows a:x->y and b:x->y) over Rational Field + sage: Aquo = A.semisimple_quotient() + sage: Aquo.central_orthogonal_idempotents() + [B['x'], B['y']] + """ + return [x.lift() + for x in self.center().central_orthogonal_idempotents()] - class Commutative(CategoryWithAxiom_over_base_ring): - class ParentMethods: + class Commutative(CategoryWithAxiom_over_base_ring): - @cached_method - def _orthogonal_decomposition(self, generators=None): - r""" - Return a maximal list of orthogonal quasi-idempotents of - this finite dimensional semisimple commutative algebra. + class ParentMethods: - INPUT: + @cached_method + def _orthogonal_decomposition(self, generators=None): + r""" + Return a maximal list of orthogonal quasi-idempotents of + this finite dimensional semisimple commutative algebra. - - ``generators`` -- a list of generators of - ``self`` (default: the basis of ``self``) + INPUT: - OUTPUT: + - ``generators`` -- a list of generators of + ``self`` (default: the basis of ``self``) - A list of quasi-idempotent elements of ``self``. + OUTPUT: - Each quasi-idempotent `e` spans a one - dimensional (non unital) subalgebra of - ``self``, and cannot be decomposed as a sum - `e=e_1+e_2` of quasi-idempotents elements. - All together, they form a basis of ``self``. + A list of quasi-idempotent elements of ``self``. - Up to the order and scalar factors, the result - is unique. In particular it does not depend on - the provided generators which are only used - for improved efficiency. + Each quasi-idempotent `e` spans a one + dimensional (non unital) subalgebra of + ``self``, and cannot be decomposed as a sum + `e=e_1+e_2` of quasi-idempotents elements. + All together, they form a basis of ``self``. - ALGORITHM: + Up to the order and scalar factors, the result + is unique. In particular it does not depend on + the provided generators which are only used + for improved efficiency. - Thanks to Schur's Lemma, a commutative - semisimple algebra `A` is a direct sum of - dimension 1 subalgebras. The algorithm is - recursive and proceeds as follows: - - 0. If `A` is of dimension 1, return a non zero - element. - - 1. Otherwise: find one of the generators such - that the morphism `x \mapsto ax` has at - least two (right) eigenspaces. - - 2. Decompose both eigenspaces recursively. - - EXAMPLES: - - We compute an orthogonal decomposition of the - center of the algebra of the symmetric group - `S_4`:: - - sage: Z4 = SymmetricGroup(4).algebra(QQ).center() - sage: Z4._orthogonal_decomposition() - [B[0] + B[1] + B[2] + B[3] + B[4], - B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], - B[0] + B[2] - 1/2*B[3], - B[0] - 1/3*B[1] - 1/3*B[2] + 1/3*B[4], - B[0] - B[1] + B[2] + B[3] - B[4]] - - .. TODO:: - - Improve speed by using matrix operations - only, or even better delegating to a - multivariate polynomial solver. - """ - if self.dimension() == 1: - return self.basis().list() - - category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() - - if generators is None: - generators = self.basis().list() - - # Searching for a good generator ... - for gen in generators: - # Computing the eigenspaces of the - # linear map x -> gen*x - phi = self.module_morphism( - on_basis=lambda i: - gen*self.term(i), - codomain=self) - eigenspaces = phi.matrix().eigenspaces_right() - - if len(eigenspaces) >= 2: - # Gotcha! Let's split the algebra according to the eigenspaces - subalgebras = [ - self.submodule(map(self.from_vector, eigenspace.basis()), - category=category) - for eigenvalue, eigenspace in eigenspaces] - - # Decompose recursively each eigenspace - return [idempotent.lift() - for subalgebra in subalgebras - for idempotent in subalgebra._orthogonal_decomposition()] - # TODO: Should this be an assertion check? - raise Exception("Unable to fully decompose %s!"%self) - - @cached_method - def central_orthogonal_idempotents(self): - r""" - Return the central orthogonal idempotents of - this semisimple commutative algebra. - - Those idempotents form a maximal decomposition - of the identity into primitive orthogonal - idempotents. - - OUTPUT: - - A list of orthogonal idempotents of ``self``. - - EXAMPLES:: - - sage: A4 = SymmetricGroup(4).algebra(QQ) - sage: Z4 = A4.center() - sage: idempotents = Z4.central_orthogonal_idempotents() - sage: idempotents - [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], - 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], - 1/6*B[0] + 1/6*B[2] - 1/12*B[3], - 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], - 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] - - Lifting those idempotents from the center, we - recognize among them the sum and alternating - sum of all permutations:: - - sage: [e.lift() for e in idempotents] - [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) - + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) - + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) - + 1/24*(1,3,4,2) + 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) - + 1/24*(1,3,2,4) + 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) - + 1/24*(1,4) + 1/24*(1,4,2,3) + 1/24*(1,4)(2,3), - ..., - 1/24*() - 1/24*(3,4) - 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) - - 1/24*(2,4) - 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) - - 1/24*(1,2,3,4) - 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) - - 1/24*(1,3,4,2) - 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) - - 1/24*(1,3,2,4) - 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) - - 1/24*(1,4) - 1/24*(1,4,2,3) + 1/24*(1,4)(2,3)] - - We check that they indeed form a decomposition - of the identity of `Z_4` into orthogonal idempotents:: - - sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) - True - """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in self._orthogonal_decomposition()] + ALGORITHM: + + Thanks to Schur's Lemma, a commutative + semisimple algebra `A` is a direct sum of + dimension 1 subalgebras. The algorithm is + recursive and proceeds as follows: + + 0. If `A` is of dimension 1, return a non zero + element. + + 1. Otherwise: find one of the generators such + that the morphism `x \mapsto ax` has at + least two (right) eigenspaces. + + 2. Decompose both eigenspaces recursively. + + EXAMPLES: + + We compute an orthogonal decomposition of the + center of the algebra of the symmetric group + `S_4`:: + + sage: Z4 = SymmetricGroup(4).algebra(QQ).center() + sage: Z4._orthogonal_decomposition() + [B[0] + B[1] + B[2] + B[3] + B[4], + B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], + B[0] + B[2] - 1/2*B[3], + B[0] - 1/3*B[1] - 1/3*B[2] + 1/3*B[4], + B[0] - B[1] + B[2] + B[3] - B[4]] + + .. TODO:: + + Improve speed by using matrix operations + only, or even better delegating to a + multivariate polynomial solver. + """ + if self.dimension() == 1: + return self.basis().list() + + category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() + + if generators is None: + generators = self.basis().list() + + # Searching for a good generator ... + for gen in generators: + # Computing the eigenspaces of the + # linear map x -> gen*x + phi = self.module_morphism( + on_basis=lambda i: + gen*self.term(i), + codomain=self) + eigenspaces = phi.matrix().eigenspaces_right() + + if len(eigenspaces) >= 2: + # Gotcha! Let's split the algebra according to the eigenspaces + subalgebras = [ + self.submodule(map(self.from_vector, eigenspace.basis()), + category=category) + for eigenvalue, eigenspace in eigenspaces] + + # Decompose recursively each eigenspace + return [idempotent.lift() + for subalgebra in subalgebras + for idempotent in subalgebra._orthogonal_decomposition()] + # TODO: Should this be an assertion check? + raise Exception("Unable to fully decompose %s!"%self) + + @cached_method + def central_orthogonal_idempotents(self): + r""" + Return the central orthogonal idempotents of + this semisimple commutative algebra. + + Those idempotents form a maximal decomposition + of the identity into primitive orthogonal + idempotents. + + OUTPUT: + + A list of orthogonal idempotents of ``self``. + + EXAMPLES:: + + sage: A4 = SymmetricGroup(4).algebra(QQ) + sage: Z4 = A4.center() + sage: idempotents = Z4.central_orthogonal_idempotents() + sage: idempotents + [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], + 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], + 1/6*B[0] + 1/6*B[2] - 1/12*B[3], + 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], + 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] + + Lifting those idempotents from the center, we + recognize among them the sum and alternating + sum of all permutations:: + + sage: [e.lift() for e in idempotents] + [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + + 1/24*(1,3,4,2) + 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + + 1/24*(1,3,2,4) + 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + + 1/24*(1,4) + 1/24*(1,4,2,3) + 1/24*(1,4)(2,3), + ..., + 1/24*() - 1/24*(3,4) - 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) + - 1/24*(2,4) - 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) + - 1/24*(1,2,3,4) - 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) + - 1/24*(1,3,4,2) - 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) + - 1/24*(1,3,2,4) - 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) + - 1/24*(1,4) - 1/24*(1,4,2,3) + 1/24*(1,4)(2,3)] + + We check that they indeed form a decomposition + of the identity of `Z_4` into orthogonal idempotents:: + + sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) + True + """ + return [(e.leading_coefficient()/(e*e).leading_coefficient())*e + for e in self._orthogonal_decomposition()] diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index bed9a2d17e3..72d022b242a 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -9,12 +9,12 @@ #****************************************************************************** from sage.misc.bindable_class import BoundClass +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport from category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.misc.cachefunc import cached_method from algebras import Algebras - class SemisimpleAlgebras(Category_over_base_ring): """ The category of semisimple algebras over a given base ring. @@ -109,205 +109,4 @@ def radical_basis(self, **keywords): class FiniteDimensional(CategoryWithAxiom_over_base_ring): - class WithBasis(CategoryWithAxiom_over_base_ring): - - class ParentMethods: - - @cached_method - def central_orthogonal_idempotents(self): - r""" - Return a maximal list of central orthogonal - idempotents of ``self``. - - *Central orthogonal idempotents* of an algebra `A` - are idempotents `(e_1, \dots, e_n)` in the center - of `A` such that `e_i e_j = 0` whenever `i \neq j`. - - With the maximality condition, they sum up to `1` - and are uniquely determined (up to order). - - INPUT: - - - ``self`` -- a semisimple algebra. - - EXAMPLES: - - For the algebra of the symmetric group `S_3`, we - recover the sum and alternating sum of all - permutations, together with a third idempotent:: - - sage: A3 = SymmetricGroup(3).algebra(QQ) - sage: idempotents = A3.central_orthogonal_idempotents() - sage: idempotents - [1/6*() + 1/6*(2,3) + 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) + 1/6*(1,3), - 2/3*() - 1/3*(1,2,3) - 1/3*(1,3,2), - 1/6*() - 1/6*(2,3) - 1/6*(1,2) + 1/6*(1,2,3) + 1/6*(1,3,2) - 1/6*(1,3)] - sage: A3.is_identity_decomposition_into_orthogonal_idempotents(idempotents) - True - - For the semisimple quotient of a quiver algebra, - we recover the vertices of the quiver:: - - sage: A = FiniteDimensionalAlgebrasWithBasis(QQ).example(); A - An example of a finite dimensional algebra with basis: - the path algebra of the Kronecker quiver (containing - the arrows a:x->y and b:x->y) over Rational Field - sage: Aquo = A.semisimple_quotient() - sage: Aquo.central_orthogonal_idempotents() - [B['x'], B['y']] - """ - return [x.lift() - for x in self.center().central_orthogonal_idempotents()] - - - class Commutative(CategoryWithAxiom_over_base_ring): - - class ParentMethods: - - @cached_method - def _orthogonal_decomposition(self, generators=None): - r""" - Return a maximal list of orthogonal quasi-idempotents of - this finite dimensional semisimple commutative algebra. - - INPUT: - - - ``generators`` -- a list of generators of - ``self`` (default: the basis of ``self``) - - OUTPUT: - - - a list of quasi-idempotent elements of ``self``. - - Each quasi-idempotent `e` spans a one - dimensional (non unital) subalgebra of - ``self``, and cannot be decomposed as a sum - `e=e_1+e_2` of quasi-idempotents elements. - All together, they form a basis of ``self``. - - Up to the order and scalar factors, the result - is unique. In particular it does not depend on - the provided generators which are only used - for improved efficiency. - - ALGORITHM: - - Thanks to Schur's Lemma, a commutative - semisimple algebra `A` is a direct sum of - dimension 1 subalgebras. The algorithm is - recursive and proceeds as follows: - - 0. If `A` is of dimension 1, return a non zero - element. - - 1. Otherwise: find one of the generators such - that the morphism `x \mapsto ax` has at - least two (right) eigenspaces. - - 2. Decompose both eigenspaces recursively. - - EXAMPLES: - - We compute an orthogonal decomposition of the - center of the algebra of the symmetric group - `S_4`:: - - sage: Z4 = SymmetricGroup(4).algebra(QQ).center() - sage: Z4._orthogonal_decomposition() - [B[0] + B[1] + B[2] + B[3] + B[4], - B[0] + 1/3*B[1] - 1/3*B[2] - 1/3*B[4], - B[0] + B[2] - 1/2*B[3], - B[0] - 1/3*B[1] - 1/3*B[2] + 1/3*B[4], - B[0] - B[1] + B[2] + B[3] - B[4]] - - .. TODO:: - - Improve speed by using matrix operations - only, or even better delegating to a - multivariate polynomial solver. - """ - if self.dimension() == 1: - return self.basis().list() - - category = Algebras(self.base_ring()).Semisimple().WithBasis().FiniteDimensional().Commutative().Subobjects() - - if generators is None: - generators = self.basis().list() - - # Searching for a good generator ... - for gen in generators: - # Computing the eigenspaces of the - # linear map x -> gen*x - phi = self.module_morphism( - on_basis=lambda i: - gen*self.term(i), - codomain=self) - eigenspaces = phi.matrix().eigenspaces_right() - - if len(eigenspaces) >= 2: - # Gotcha! Let's split the algebra according to the eigenspaces - subalgebras = [ - self.submodule(map(self.from_vector, eigenspace.basis()), - category=category) - for eigenvalue, eigenspace in eigenspaces] - - # Decompose recursively each eigenspace - return [idempotent.lift() - for subalgebra in subalgebras - for idempotent in subalgebra._orthogonal_decomposition()] - # TODO: Should this be an assertion check? - raise Exception("Unable to fully decompose %s!"%self) - - @cached_method - def central_orthogonal_idempotents(self): - r""" - Return the central orthogonal idempotents of - this semisimple commutative algebra. - - Those idempotents form a maximal decomposition - of the identity into primitive orthogonal - idempotents. - - OUTPUT: - - - a list of orthogonal idempotents of ``self``. - - EXAMPLES:: - - sage: A4 = SymmetricGroup(4).algebra(QQ) - sage: Z4 = A4.center() - sage: idempotents = Z4.central_orthogonal_idempotents() - sage: idempotents - [1/24*B[0] + 1/24*B[1] + 1/24*B[2] + 1/24*B[3] + 1/24*B[4], - 3/8*B[0] + 1/8*B[1] - 1/8*B[2] - 1/8*B[4], - 1/6*B[0] + 1/6*B[2] - 1/12*B[3], - 3/8*B[0] - 1/8*B[1] - 1/8*B[2] + 1/8*B[4], - 1/24*B[0] - 1/24*B[1] + 1/24*B[2] + 1/24*B[3] - 1/24*B[4]] - - Lifting those idempotents from the center, we - recognize among them the sum and alternating - sum of all permutations:: - - sage: [e.lift() for e in idempotents] - [1/24*() + 1/24*(3,4) + 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) - + 1/24*(2,4) + 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) - + 1/24*(1,2,3,4) + 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) - + 1/24*(1,3,4,2) + 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) - + 1/24*(1,3,2,4) + 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) - + 1/24*(1,4) + 1/24*(1,4,2,3) + 1/24*(1,4)(2,3), - ..., - 1/24*() - 1/24*(3,4) - 1/24*(2,3) + 1/24*(2,3,4) + 1/24*(2,4,3) - - 1/24*(2,4) - 1/24*(1,2) + 1/24*(1,2)(3,4) + 1/24*(1,2,3) - - 1/24*(1,2,3,4) - 1/24*(1,2,4,3) + 1/24*(1,2,4) + 1/24*(1,3,2) - - 1/24*(1,3,4,2) - 1/24*(1,3) + 1/24*(1,3,4) + 1/24*(1,3)(2,4) - - 1/24*(1,3,2,4) - 1/24*(1,4,3,2) + 1/24*(1,4,2) + 1/24*(1,4,3) - - 1/24*(1,4) - 1/24*(1,4,2,3) + 1/24*(1,4)(2,3)] - - We check that they indeed form a decomposition - of the identity of `Z_4` into orthogonal idempotents:: - - sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) - True - """ - return [(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in self._orthogonal_decomposition()] + WithBasis = LazyImport('sage.categories.finite_dimensional_semisimple_algebras_with_basis', 'FiniteDimensionalSemisimpleAlgebrasWithBasis') From bac4f1203fbf538eccb77ff3520e2a43d6263da7 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 09:35:38 +0200 Subject: [PATCH 641/665] trac #18355: Rename Stock.google->history and Stock.yahoo->current_price_data --- src/sage/finance/stock.py | 62 ++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index c438ca2c9d6..c3b53c97db8 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -15,7 +15,7 @@ sage: loads(dumps(ohlc)) == ohlc True """ - +from sage.misc.superseded import deprecated_function_alias import urllib from sage.structure.all import Sequence from datetime import date @@ -93,7 +93,7 @@ def __init__(self, symbol, cid=''): .. NOTE:: Currently, the symbol and cid do not have to match. When using - ``google()``, the cid will take precedence. + :meth:`history`, the cid will take precedence. EXAMPLES:: @@ -128,19 +128,29 @@ def market_value(self): sage: finance.Stock('goog').market_value() # random; optional - internet 575.83000000000004 """ - return float(self.yahoo()['price']) + return float(self.current_price_data()['price']) - def yahoo(self): - """ + def current_price_data(self): + r""" Get Yahoo current price data for this stock. - OUTPUT: + This method returns a dictionary wit the following keys: - A dictionary. + + .. csv-table:: + :class: contentstable + :widths: 25,25,25,25 + :delim: | + + ``'price'`` | ``'change'`` | ``'volume'`` | ``'avg_daily_volume'`` + ``'stock_exchange'`` | ``'market_cap'`` | ``'book_value'`` | ``'ebitda'`` + ``'dividend_per_share'`` | ``'dividend_yield'`` | ``'earnings_per_share'`` | ``'52_week_high'`` + ``'52_week_low'`` | ``'50day_moving_avg'`` | ``'200day_moving_avg'`` | ``'price_earnings_ratio'`` + ``'price_earnings_growth_ratio'`` | ``'price_sales_ratio'`` | ``'price_book_ratio'`` | ``'short_ratio'``. EXAMPLES:: - sage: finance.Stock('GOOG').yahoo() # optional -- internet + sage: finance.Stock('GOOG').current_price_data() # optional -- internet {'stock_exchange': '"NasdaqNM"', 'market_cap': '...', '200day_moving_avg': '...', '52_week_high': '...', 'price_earnings_growth_ratio': '...', 'price_sales_ratio': '...', 'price': '...', 'earnings_per_share': '...', '50day_moving_avg': '...', 'avg_daily_volume': '...', 'volume': '...', '52_week_low': '...', 'short_ratio': '...', 'price_earnings_ratio': '...', 'dividend_yield': '...', 'dividend_per_share': '...', 'price_book_ratio': '...', 'ebitda': '...', 'change': '...', 'book_value': '...'} """ url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (self.symbol, 'l1c1va2xj1b4j4dyekjm3m4rr5p5p6s7') @@ -168,7 +178,9 @@ def yahoo(self): data['short_ratio'] = values[19] return data - def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y"), histperiod='daily'): + yahoo = deprecated_function_alias(1000,current_price_data) + + def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y"), histperiod='daily'): """ Return an immutable sequence of historical price data for this stock, obtained from Google. OHLC data is stored @@ -186,7 +198,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y public. By default, this function only looks at the NASDAQ and NYSE markets. However, if you specified the market during initialization of the stock (i.e. ``finance.Stock("OTC:NTDOY")``), - ``Stock.google()`` will give correct results. + this method will give correct results. INPUT: @@ -204,7 +216,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y We get the first five days of VMware's stock history:: - sage: finance.Stock('vmw').google('Aug+13,+2007')[:5] # optional -- internet + sage: finance.Stock('vmw').history('Aug+13,+2007')[:5] # optional -- internet [ 14-Aug-07 51.99 55.50 48.00 51.00 38253700, 15-Aug-07 52.11 59.87 51.50 57.71 10487000, @@ -213,7 +225,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y 20-Aug-07 56.05 57.50 55.61 57.33 2077200 ] - sage: finance.Stock('F').google('Jan+3,+1978', 'Jul+7,+2008')[:5] # optional -- internet + sage: finance.Stock('F').history('Jan+3,+1978', 'Jul+7,+2008')[:5] # optional -- internet [ 3-Jan-78 0.00 1.93 1.89 1.89 1618200, 4-Jan-78 0.00 1.89 1.87 1.88 2482700, @@ -227,7 +239,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y leading up to the specified end date. For example, Apple's (AAPL) stock history only dates back to September 7, 1984:: - sage: finance.Stock('AAPL').google('Sep+1,+1900', 'Jan+1,+2000')[0:5] # optional -- internet + sage: finance.Stock('AAPL').history('Sep+1,+1900', 'Jan+1,+2000')[0:5] # optional -- internet [ 4-Jan-99 0.00 2.64 2.50 2.58 136126400, 5-Jan-99 0.00 2.75 2.59 2.71 201441600, @@ -239,7 +251,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y Here is an example where we create and get the history of a stock that is not in NASDAQ or NYSE:: - sage: finance.Stock("OTC:NTDOY").google(startdate="Jan+1,+2007", enddate="Jan+1,+2008")[:5] # optional -- internet + sage: finance.Stock("OTC:NTDOY").history(startdate="Jan+1,+2007", enddate="Jan+1,+2008")[:5] # optional -- internet [ 3-Jan-07 32.44 32.75 32.30 32.44 156283, 4-Jan-07 31.70 32.40 31.20 31.70 222643, @@ -255,7 +267,7 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y the symbol and cid do not match, the history based on the contract id will be returned. :: - sage: sage.finance.stock.Stock("AAPL", 22144).google(startdate='Jan+1,+1990')[:5] #optional -- internet + sage: sage.finance.stock.Stock("AAPL", 22144).history(startdate='Jan+1,+1990')[:5] #optional -- internet [ 2-Jan-90 0.00 9.38 8.75 9.31 6542800, 3-Jan-90 0.00 9.50 9.38 9.38 7428400, @@ -282,6 +294,8 @@ def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y self.__historical = self._load_from_csv(R) return self.__historical + google = deprecated_function_alias(1000,history) + def open(self, *args, **kwds): r""" Return a time series containing historical opening prices for this @@ -311,7 +325,7 @@ def open(self, *args, **kwds): data:: sage: c = finance.Stock('vmw') # optional -- internet - sage: c.google(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet + sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet [ 1-Feb-08 56.98 58.14 55.06 57.85 2473000, 4-Feb-08 58.00 60.47 56.91 58.05 1816500, @@ -322,7 +336,7 @@ def open(self, *args, **kwds): sage: c.open() # optional -- internet [56.9800, 58.0000, 57.6000, 60.3200, ... 56.5500, 59.3000, 60.0000, 59.7900, 59.2600] - Otherwise, ``self.google()`` will be called with the default + Otherwise, :meth:`history` will be called with the default arguments returning a year's worth of data:: sage: finance.Stock('vmw').open() # random; optional -- internet @@ -332,14 +346,14 @@ def open(self, *args, **kwds): from time_series import TimeSeries if len(args) != 0: - return TimeSeries([x.open for x in self.google(*args, **kwds)]) + return TimeSeries([x.open for x in self.history(*args, **kwds)]) try: return TimeSeries([x.open for x in self.__historical]) except AttributeError: pass - return TimeSeries([x.open for x in self.google(*args, **kwds)]) + return TimeSeries([x.open for x in self.history(*args, **kwds)]) def close(self, *args, **kwds): r""" @@ -370,7 +384,7 @@ def close(self, *args, **kwds): data:: sage: c = finance.Stock('vmw') # optional -- internet - sage: c.google(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet + sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet [ 1-Feb-08 56.98 58.14 55.06 57.85 2473000, 4-Feb-08 58.00 60.47 56.91 58.05 1816500, @@ -381,7 +395,7 @@ def close(self, *args, **kwds): sage: c.close() # optional -- internet [57.8500, 58.0500, 59.3000, 61.5200, ... 58.2900, 60.1800, 59.8600, 59.9500, 58.6700] - Otherwise, ``self.google()`` will be called with the default + Otherwise, :meth:`history` will be called with the default arguments returning a year's worth of data:: sage: finance.Stock('vmw').close() # random; optional -- internet @@ -391,14 +405,14 @@ def close(self, *args, **kwds): from time_series import TimeSeries if len(args) != 0: - return TimeSeries([x.close for x in self.google(*args, **kwds)]) + return TimeSeries([x.close for x in self.history(*args, **kwds)]) try: return TimeSeries([x.close for x in self.__historical]) except AttributeError: pass - return TimeSeries([x.close for x in self.google(*args, **kwds)]) + return TimeSeries([x.close for x in self.history(*args, **kwds)]) def load_from_file(self, file): r""" @@ -503,7 +517,7 @@ def _get_data(self, exchange='', startdate='Jan+1,+1900', enddate=date.today().s This indirectly tests the use of ``_get_data()``:: - sage: finance.Stock('aapl').google(startdate='Jan+1,+1990',enddate='Jan+1,+1991')[:2] # optional -- internet + sage: finance.Stock('aapl').history(startdate='Jan+1,+1990',enddate='Jan+1,+1991')[:2] # optional -- internet [ 2-Jan-90 0.00 2.34 2.19 2.33 26171200, 3-Jan-90 0.00 2.38 2.34 2.34 29713600 From 4481fbc206844cbe6da46b7e360d7c0149ff7600 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 09:48:37 +0200 Subject: [PATCH 642/665] trac #18355: Index of methods --- src/sage/finance/stock.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index c3b53c97db8..b32120a4929 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -1,6 +1,20 @@ -""" +r""" Stock Market Price Series +This module's main class is :class:`Stock`. It defines the following methods: + +.. csv-table:: + :class: contentstable + :widths: 20,80 + :delim: | + + :meth:`~sage.finance.stock.Stock.market_value` | Return the current market value of this stock. + :meth:`~sage.finance.stock.Stock.current_price_data` | Get Yahoo current price data for this stock. + :meth:`~sage.finance.stock.Stock.history` | Return an immutable sequence of historical price data for this stock + :meth:`~sage.finance.stock.Stock.open` | Return a time series containing historical opening prices for this stock. + :meth:`~sage.finance.stock.Stock.close` | Return the time series of all historical closing prices for this stock. + :meth:`~sage.finance.stock.Stock.load_from_file` | Load historical data from a local csv formatted data file. + AUTHORS: - William Stein, 2008 @@ -14,6 +28,9 @@ sage: ohlc = sage.finance.stock.OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092) sage: loads(dumps(ohlc)) == ohlc True + +Classes and methods +------------------- """ from sage.misc.superseded import deprecated_function_alias import urllib From ac967553c17a5966312eae8abd73a30e17ac10ed Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 10:14:29 +0200 Subject: [PATCH 643/665] trac #18355: Raise exceptions in Stock._get_data instead of doing it in higher-level functions --- src/sage/finance/stock.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index b32120a4929..f77aeea6a4f 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -300,13 +300,12 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% if ':' in symbol: R = self._get_data('', startdate, enddate, histperiod) else: - R = self._get_data('NASDAQ:', startdate, enddate, histperiod) - if "Bad Request" in R: + try: + R = self._get_data('NASDAQ:', startdate, enddate, histperiod) + except RuntimeError: R = self._get_data("NYSE:", startdate, enddate, histperiod) else: R = self._get_data('', startdate, enddate, histperiod) - if "Bad Request" in R: - raise RuntimeError self.__historical = [] self.__historical = self._load_from_csv(R) return self.__historical @@ -539,6 +538,13 @@ def _get_data(self, exchange='', startdate='Jan+1,+1900', enddate=date.today().s 2-Jan-90 0.00 2.34 2.19 2.33 26171200, 3-Jan-90 0.00 2.38 2.34 2.34 29713600 ] + + TESTS:: + + sage: finance.Stock('whatever').history() # optional -- internet + Traceback (most recent call last): + ... + RuntimeError: Google reported a wrong request (did you specify a cid?) """ symbol = self.symbol cid = self.cid @@ -546,4 +552,7 @@ def _get_data(self, exchange='', startdate='Jan+1,+1900', enddate=date.today().s url = 'http://finance.google.com/finance/historical?q=%s%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(exchange, symbol.upper(), startdate, enddate, histperiod) else: url = 'http://finance.google.com/finance/historical?cid=%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(cid, startdate, enddate, histperiod) - return urllib.urlopen(url).read() + data = urllib.urlopen(url).read() + if "Bad Request" in data or "The requested URL was not found on this server." in data: + raise RuntimeError("Google reported a wrong request (did you specify a cid?)") + return data From ec9bd1d3bf9ff79d02a2ee8b4611d4aadc72c7aa Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 10:27:13 +0200 Subject: [PATCH 644/665] trac #18355: Fix one broken doctest --- src/sage/finance/stock.py | 48 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index f77aeea6a4f..b918f9efeb0 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -167,8 +167,51 @@ def current_price_data(self): EXAMPLES:: - sage: finance.Stock('GOOG').current_price_data() # optional -- internet - {'stock_exchange': '"NasdaqNM"', 'market_cap': '...', '200day_moving_avg': '...', '52_week_high': '...', 'price_earnings_growth_ratio': '...', 'price_sales_ratio': '...', 'price': '...', 'earnings_per_share': '...', '50day_moving_avg': '...', 'avg_daily_volume': '...', 'volume': '...', '52_week_low': '...', 'short_ratio': '...', 'price_earnings_ratio': '...', 'dividend_yield': '...', 'dividend_per_share': '...', 'price_book_ratio': '...', 'ebitda': '...', 'change': '...', 'book_value': '...'} + sage: finance.Stock('GOOG').current_price_data() # random + {'200day_moving_avg': '536.57', + '50day_moving_avg': '546.01', + '52_week_high': '599.65', + '52_week_low': '487.56', + 'avg_daily_volume': '1826450', + 'book_value': '153.64', + 'change': '+0.56', + 'dividend_per_share': 'N/A', + 'dividend_yield': 'N/A', + 'earnings_per_share': '20.99', + 'ebitda': '21.48B', + 'market_cap': '366.11B', + 'price': '537.90', + 'price_book_ratio': '3.50', + 'price_earnings_growth_ratio': '0.00', + 'price_earnings_ratio': '25.62', + 'price_sales_ratio': '5.54', + 'short_ratio': '1.50', + 'stock_exchange': '"NMS"', + 'volume': '1768181'} + + TESTS:: + + sage: finance.Stock('GOOG').current_price_data() # optional -- internet + {'200day_moving_avg': ..., + '50day_moving_avg': ..., + '52_week_high': ..., + '52_week_low': ..., + 'avg_daily_volume': ..., + 'book_value': ..., + 'change': ..., + 'dividend_per_share': ..., + 'dividend_yield': ..., + 'earnings_per_share': ..., + 'ebitda': ..., + 'market_cap': ..., + 'price': ..., + 'price_book_ratio': ..., + 'price_earnings_growth_ratio': ..., + 'price_earnings_ratio': ..., + 'price_sales_ratio': ..., + 'short_ratio': ..., + 'stock_exchange': ..., + 'volume': ...} """ url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (self.symbol, 'l1c1va2xj1b4j4dyekjm3m4rr5p5p6s7') values = urllib.urlopen(url).read().strip().strip('"').split(',') @@ -292,6 +335,7 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% 5-Jan-90 0.00 9.56 9.25 9.44 4404000, 8-Jan-90 0.00 9.50 9.25 9.50 3627600 ] + """ cid = self.cid symbol = self.symbol From bce3bc4ae710a4eaea99587d9bffffe4f89f18f2 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 10:29:04 +0200 Subject: [PATCH 645/665] trac #18355: Add actual ticket number in the deprecations --- src/sage/finance/stock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index b918f9efeb0..321fcc0d849 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -238,7 +238,7 @@ def current_price_data(self): data['short_ratio'] = values[19] return data - yahoo = deprecated_function_alias(1000,current_price_data) + yahoo = deprecated_function_alias(18355,current_price_data) def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y"), histperiod='daily'): """ @@ -354,7 +354,7 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% self.__historical = self._load_from_csv(R) return self.__historical - google = deprecated_function_alias(1000,history) + google = deprecated_function_alias(18355,history) def open(self, *args, **kwds): r""" From 465271f1e9f0fa42b72cd050d590ea325d4175d6 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 3 May 2015 10:48:41 +0200 Subject: [PATCH 646/665] Trac 18332: remove is_rational_c, add is_one --- .../number_field/number_field_element.pxd | 1 - .../number_field/number_field_element.pyx | 81 ++++++++++--------- .../number_field_element_quadratic.pyx | 35 ++++++-- 3 files changed, 73 insertions(+), 44 deletions(-) diff --git a/src/sage/rings/number_field/number_field_element.pxd b/src/sage/rings/number_field/number_field_element.pxd index f95ead5f80a..76fbdf67957 100644 --- a/src/sage/rings/number_field/number_field_element.pxd +++ b/src/sage/rings/number_field/number_field_element.pxd @@ -34,7 +34,6 @@ cdef class NumberFieldElement(FieldElement): cpdef ModuleElement _sub_(self, ModuleElement right) cpdef ModuleElement _neg_(self) - cdef bint is_rational_c(self) cdef int _randomize(self, num_bound, den_bound, distribution) except -1 diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index fb15273f194..157b9c47e1a 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2588,41 +2588,32 @@ cdef class NumberFieldElement(FieldElement): True """ - if self.__multiplicative_order is not None: - return self.__multiplicative_order - - one = self.number_field().one() - infinity = sage.rings.infinity.infinity - - if self == one: - self.__multiplicative_order = ZZ(1) - return self.__multiplicative_order - if self == -one: - self.__multiplicative_order = ZZ(2) - return self.__multiplicative_order - - if isinstance(self.number_field(), number_field.NumberField_cyclotomic): - t = self.number_field()._multiplicative_order_table() - f = self.polynomial() - if f in t: - self.__multiplicative_order = t[f] - return self.__multiplicative_order - else: + if self.__multiplicative_order is None: + if self.is_rational(): + if self.is_one(): + self.__multiplicative_order = ZZ(1) + elif (-self).is_one(): + self.__multiplicative_order = ZZ(2) + else: + self.__multiplicative_order = sage.rings.infinity.infinity + elif not (self.is_integral() and self.norm().is_one()): self.__multiplicative_order = sage.rings.infinity.infinity - return self.__multiplicative_order - - if self.is_rational_c() or not self.is_integral() or not self.norm() ==1: - self.__multiplicative_order = infinity - return self.__multiplicative_order - - # Now we have a unit of norm 1, and check if it is a root of unity + elif isinstance(self.number_field(), number_field.NumberField_cyclotomic): + t = self.number_field()._multiplicative_order_table() + f = self.polynomial() + if f in t: + self.__multiplicative_order = t[f] + else: + self.__multiplicative_order = sage.rings.infinity.infinity + else: + # Now we have a unit of norm 1, and check if it is a root of unity + n = self.number_field().zeta_order() + if not self**n ==1: + self.__multiplicative_order = sage.rings.infinity.infinity + else: + from sage.groups.generic import order_from_multiple + self.__multiplicative_order = order_from_multiple(self,n,operation='*') - n = self.number_field().zeta_order() - if not self**n ==1: - self.__multiplicative_order = infinity - return self.__multiplicative_order - from sage.groups.generic import order_from_multiple - self.__multiplicative_order = order_from_multiple(self,n,operation='*') return self.__multiplicative_order def additive_order(self): @@ -2640,11 +2631,29 @@ cdef class NumberFieldElement(FieldElement): sage: K.ring_of_integers().characteristic() # implicit doctest 0 """ - if self == 0: return 1 + if not self: return ZZ.one() else: return sage.rings.infinity.infinity - cdef bint is_rational_c(self): - return ZZX_deg(self.__numerator) == 0 + def is_one(self): + r""" + Test whether this number field element is `1`. + + EXAMPLES:: + + sage: K. = NumberField(x^3 + 3) + sage: K(1).is_one() + True + sage: K(0).is_one() + False + sage: K(-1).is_one() + False + sage: K(1/2).is_one() + False + sage: a.is_one() + False + """ + return ZZX_IsOne(self.__numerator) == 1 and \ + ZZ_IsOne(self.__denominator) == 1 def is_rational(self): r""" diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 493dace652f..c74c7dbeb72 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -1340,6 +1340,8 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): def __nonzero__(self): """ + Check whether this element is not zero. + EXAMPLES:: sage: K. = NumberField(x^2+163) @@ -1350,7 +1352,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ return mpz_cmp_ui(self.a, 0) != 0 or mpz_cmp_ui(self.b, 0) != 0 - def _integer_(self, Z=None): """ EXAMPLES: @@ -1370,7 +1371,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_set(res.value, self.a) return res - def _rational_(self): """ EXAMPLES: @@ -1392,6 +1392,30 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpq_canonicalize(res.value) return res + def is_one(self): + r""" + Check whether this number field element is `1`. + + EXAMPLES:: + + sage: K = QuadraticField(-2) + sage: K(1).is_one() + True + sage: K(-1).is_one() + False + sage: K(2).is_one() + False + sage: K(0).is_one() + False + sage: K(1/2).is_one() + False + sage: K.gen().is_one() + False + """ + return mpz_cmp_ui(self.a, 1) == 0 and \ + mpz_cmp_ui(self.b, 0) == 0 and \ + mpz_cmp_ui(self.denom, 1) == 0 + def is_rational(self): r""" Check whether this number field element is a rational number. @@ -1634,9 +1658,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): """ return self*self.denominator() - cdef bint is_rational_c(self): - return mpz_cmp_ui(self.b, 0) == 0 - ######################################################### # Some things are so much easier to compute @@ -1807,7 +1828,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: (a+1/2-a).minpoly() x - 1/2 """ - if self.is_rational_c(): + if self.is_rational(): R = QQ[var] return R([-self._rational_(), 1]) else: @@ -2038,7 +2059,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): sage: R(5).minpoly() x - 5 """ - if self.is_rational_c(): + if self.is_rational(): R = ZZ[var] return R([-self._rational_(), 1]) else: From 8fa6326cc34cdb44566758832111cbbc3542f46a Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 3 May 2015 12:32:55 +0200 Subject: [PATCH 647/665] Trac 18332: two def -> cpdef + documentation --- .../rings/number_field/number_field_element.pxd | 2 ++ .../rings/number_field/number_field_element.pyx | 16 +++++++++++++--- .../number_field_element_quadratic.pyx | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/number_field/number_field_element.pxd b/src/sage/rings/number_field/number_field_element.pxd index 76fbdf67957..9470e41e5ef 100644 --- a/src/sage/rings/number_field/number_field_element.pxd +++ b/src/sage/rings/number_field/number_field_element.pxd @@ -34,6 +34,8 @@ cdef class NumberFieldElement(FieldElement): cpdef ModuleElement _sub_(self, ModuleElement right) cpdef ModuleElement _neg_(self) + cpdef bint is_rational(self) + cpdef bint is_one(self) cdef int _randomize(self, num_bound, den_bound, distribution) except -1 diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 157b9c47e1a..9987714ad30 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2634,7 +2634,7 @@ cdef class NumberFieldElement(FieldElement): if not self: return ZZ.one() else: return sage.rings.infinity.infinity - def is_one(self): + cpdef bint is_one(self): r""" Test whether this number field element is `1`. @@ -2655,9 +2655,14 @@ cdef class NumberFieldElement(FieldElement): return ZZX_IsOne(self.__numerator) == 1 and \ ZZ_IsOne(self.__denominator) == 1 - def is_rational(self): + cpdef bint is_rational(self): r""" - Test whether this number field element is a rational + Test whether this number field element is a rational number + + .. SEEALSO: + + - :meth:`is_integer` to test if this element is an integer + - :meth:`is_integral` to test if this element is an algebraic integer EXAMPLES:: @@ -2679,6 +2684,11 @@ cdef class NumberFieldElement(FieldElement): r""" Test whether this number field element is an integer + .. SEEALSO: + + - :meth:`is_rational` to test if this element is a rational number + - :meth:`is_integral` to test if this element is an algebraic integer + EXAMPLES:: sage: K. = NumberField(x^3 - 3) diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index c74c7dbeb72..4d551c1320b 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -1392,7 +1392,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpq_canonicalize(res.value) return res - def is_one(self): + cpdef bint is_one(self): r""" Check whether this number field element is `1`. @@ -1416,10 +1416,15 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpz_cmp_ui(self.b, 0) == 0 and \ mpz_cmp_ui(self.denom, 1) == 0 - def is_rational(self): + cpdef bint is_rational(self): r""" Check whether this number field element is a rational number. + .. SEEALSO: + + - :meth:`is_integer` to test if this element is an integer + - :meth:`is_integral` to test if this element is an algebraic integer + EXAMPLES:: sage: K. = QuadraticField(3) @@ -1440,6 +1445,11 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): r""" Check whether this number field element is an integer. + .. SEEALSO: + + - :meth:`is_rational` to test if this element is a rational number + - :meth:`is_integral` to test if this element is an algebraic integer + EXAMPLES:: sage: K. = QuadraticField(3) From e8df618e3a7fa04547c1cc1f4195eb837f679bdf Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Sun, 3 May 2015 17:19:59 +0200 Subject: [PATCH 648/665] Trac 18346: some cleanup - remove old cython "for i from 0 <= i < n" - remove "cdef object" - replace len(list(my_iterator)) == n by counting - add a tiny bit of documentation about vertex_labels/vertex_ints --- src/sage/graphs/base/c_graph.pxd | 4 +- src/sage/graphs/base/c_graph.pyx | 93 +++++++++++++++++--------------- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pxd b/src/sage/graphs/base/c_graph.pxd index 139dab556ef..5a3ffa79278 100644 --- a/src/sage/graphs/base/c_graph.pxd +++ b/src/sage/graphs/base/c_graph.pxd @@ -35,7 +35,7 @@ cdef class CGraph: cpdef list in_neighbors(self, int v) cpdef list out_neighbors(self, int u) cpdef list verts(self) - cpdef add_vertices(self, object verts) + cpdef add_vertices(self, verts) cdef int del_vertex_unsafe(self, int) except -1 cpdef realloc(self, int) cdef int add_vertex_unsafe(self, int) except -1 @@ -43,7 +43,7 @@ cdef class CGraph: cdef class CGraphBackend(GenericGraphBackend): cdef int get_vertex(self, u) except ? -2 cdef vertex_label(self, int u_int) - cdef int check_labelled_vertex(self, object u, bint reverse) except ? -1 + cdef int check_labelled_vertex(self, u, bint reverse) except ? -1 cdef CGraph _cg cdef CGraph _cg_rev cdef bint _directed diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index d8db449173e..95d07395592 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -317,7 +317,7 @@ cdef class CGraph: self.realloc(2 * self.active_vertices.size) return self.add_vertex_unsafe(k) - cpdef add_vertices(self, object verts): + cpdef add_vertices(self, verts): """ Adds vertices from the iterable ``verts``. @@ -376,7 +376,7 @@ cdef class CGraph: nones += 1 new_names = [] - while nones > 0: + while nones: new_names.append(self.add_vertex()) nones -= 1 @@ -412,10 +412,10 @@ cdef class CGraph: raise RuntimeError("Failure allocating memory.") # delete each arc incident with v num_nbrs = self.in_neighbors_unsafe(v, neighbors, size) - for i from 0 <= i < num_nbrs: + for i in range(num_nbrs): self.del_arc_unsafe(neighbors[i], v) num_nbrs = self.out_neighbors_unsafe(v, neighbors, size) - for i from 0 <= i < num_nbrs: + for i in range(num_nbrs): self.del_arc_unsafe(v, neighbors[i]) sage_free(neighbors) @@ -614,7 +614,7 @@ cdef class CGraph: [1, 2] """ cdef int i - return [i for i from 0 <= i < self.active_vertices.size + return [i for i in range(self.active_vertices.size) if bitset_in(self.active_vertices, i)] cpdef realloc(self, int total): @@ -881,8 +881,8 @@ cdef class CGraph: ``(v, vertices[i])`` instead of ``(vertices[i], v)`` (the difference only matters for digraphs). """ - cdef int i = 0 - for 0 <= i < n: + cdef int i + for i in range(n): sequence[i] = self.has_arc_unsafe(vertices[i], v) cdef adjacency_sequence_out(self, int n, int *vertices, int v, int* sequence): @@ -922,8 +922,8 @@ cdef class CGraph: difference only matters for digraphs). """ - cdef int i = 0 - for 0 <= i < n: + cdef int i + for i in range(n): sequence[i] = self.has_arc_unsafe(v, vertices[i]) cpdef list all_arcs(self, int u, int v): @@ -1144,6 +1144,15 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G.edges(labels=False) [(0, 1), (0, 3), (4, 5), (9, 23)] + This class handles the labels of vertices and edges. For vertices it uses + two dictionaries ``vertex_labels`` and ``vertex_ints``. They are just + opposite of each other: ``vertex_ints`` makes a translation from label to + integers (that are internally used) and ``vertex_labels`` make the + translation from internally used integers to actual labels. This class tries + hard to avoid translation if possible. This will work only if the graph is + built on integers from `0` to `n-1` and the vertices are basically added in + increasing order. + .. SEEALSO:: - :class:`SparseGraphBackend ` @@ -1152,7 +1161,6 @@ cdef class CGraphBackend(GenericGraphBackend): - :class:`DenseGraphBackend ` -- backend for dense graphs. """ - cdef int get_vertex(self, u) except ? -2: """ Returns an int representing the arbitrary hashable vertex u (whether or not @@ -1212,25 +1220,21 @@ cdef class CGraphBackend(GenericGraphBackend): Returns the object represented by u_int, or None if this does not represent a vertex. """ - cdef dict vertex_ints = self.vertex_ints cdef dict vertex_labels = self.vertex_labels, - cdef CGraph G = self._cg if u_int in vertex_labels: return vertex_labels[u_int] - elif bitset_in(G.active_vertices, u_int): + elif bitset_in(self._cg.active_vertices, u_int): return u_int else: return None - cdef int check_labelled_vertex(self, object u, bint reverse) except ? -1: + cdef int check_labelled_vertex(self, u, bint reverse) except ? -1: """ Returns an int representing the arbitrary hashable vertex u, and updates, if necessary, the translation dict and list. Adds a vertex if the label is new. """ - cdef dict vertex_ints = self.vertex_ints - cdef dict vertex_labels = self.vertex_labels, cdef CGraph G = self._cg cdef CGraph G_rev = self._cg_rev @@ -1249,8 +1253,9 @@ cdef class CGraphBackend(GenericGraphBackend): if reverse: G_rev.realloc(2*G_rev.active_vertices.size) return self.check_labelled_vertex(u, reverse) - vertex_labels[u_int] = u - vertex_ints[u] = u_int + + self.vertex_labels[u_int] = u + self.vertex_ints[u] = u_int G.add_vertex(u_int) if reverse: G_rev.add_vertex(u_int) @@ -1278,11 +1283,7 @@ cdef class CGraphBackend(GenericGraphBackend): False """ cdef int v_int = self.get_vertex(v) - if v_int == -1: - return False - if not bitset_in((self._cg).active_vertices, v_int): - return False - return True + return v_int != -1 and bitset_in((self._cg).active_vertices, v_int) def c_graph(self): r""" @@ -1489,7 +1490,7 @@ cdef class CGraphBackend(GenericGraphBackend): return self._cg_rev._out_degree(v_int) - def add_vertex(self, object name): + def add_vertex(self, name): """ Add a vertex to ``self``. @@ -1544,7 +1545,7 @@ cdef class CGraphBackend(GenericGraphBackend): return retval - def add_vertices(self, object vertices): + def add_vertices(self, vertices): """ Add vertices to ``self``. @@ -1585,7 +1586,6 @@ cdef class CGraphBackend(GenericGraphBackend): sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_vertices([10,11,12]) """ - cdef object v cdef int nones = 0 for v in vertices: if v is not None: @@ -1594,11 +1594,11 @@ cdef class CGraphBackend(GenericGraphBackend): nones += 1 new_names = [] - while nones > 0: + while nones: new_names.append(self.add_vertex(None)) nones -= 1 - return new_names if new_names != [] else None + return new_names if new_names else None def del_vertex(self, v): """ @@ -1682,7 +1682,6 @@ cdef class CGraphBackend(GenericGraphBackend): sage: D.has_vertex(0) True """ - cdef object v for v in vertices: self.del_vertex(v) @@ -1827,17 +1826,16 @@ cdef class CGraphBackend(GenericGraphBackend): [1, 2] """ cdef int i - cdef object v if verts is None: S = set(self.vertex_ints.iterkeys()) - for i from 0 <= i < (self._cg).active_vertices.size: + for i in range((self._cg).active_vertices.size): if (i not in self.vertex_labels and bitset_in((self._cg).active_vertices, i)): S.add(i) return iter(S) - is_hashable = False + cdef bint is_hashable = False try: - v = hash(verts) + hash(verts) is_hashable = True except Exception: pass @@ -2045,7 +2043,6 @@ cdef class CGraphBackend(GenericGraphBackend): (8, 9, None)] """ cdef int i - cdef object v cdef dict new_vx_ints = {} cdef dict new_vx_labels = {} for v in self.iterator_verts(None): @@ -2240,8 +2237,6 @@ cdef class CGraphBackend(GenericGraphBackend): cdef float edge_label cdef int side cdef float f_tmp - cdef object v_obj - cdef object w_obj # Each vertex knows its predecessors in the search, for each side cdef dict pred_x = {} @@ -2619,7 +2614,10 @@ cdef class CGraphBackend(GenericGraphBackend): if v_int == -1: return True v = self.vertex_label(v_int) - return len(list(self.depth_first_search(v, ignore_direction=True))) == cg.num_verts + cdef int n = 0 + for _ in self.depth_first_search(v, ignore_direction=True): + n += 1 + return n == cg.num_verts def is_strongly_connected(self): r""" @@ -2640,17 +2638,25 @@ cdef class CGraphBackend(GenericGraphBackend): False """ cdef int v_int = 0 + cdef CGraph cg = self._cg # Pick one vertex - v_int = bitset_first((self._cg).active_vertices) + v_int = bitset_first(cg.active_vertices) if v_int == -1: return True v = self.vertex_label(v_int) - return (self._cg).num_verts == len(list(self.depth_first_search(v))) and \ - (self._cg).num_verts == len(list(self.depth_first_search(v, reverse=True))) + cdef int n = 0 + for _ in self.depth_first_search(v): + n += 1 + if cg.num_verts != n: + return False + n = 0 + for _ in self.depth_first_search(v, reverse=True): + n += 1 + return cg.num_verts == n def strongly_connected_component_containing_vertex(self, v): r""" @@ -2676,10 +2682,9 @@ cdef class CGraphBackend(GenericGraphBackend): sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v in g]) True """ - cdef int v_int = self.get_vertex(v) - cdef set a = set(self.depth_first_search(v)) - cdef set b = set(self.depth_first_search(v, reverse=True)) - return list(a & b) + cdef set ans = set(self.depth_first_search(v)) + ans.intersection_update(self.depth_first_search(v, reverse=True)) + return list(ans) def is_directed_acyclic(self, certificate = False): r""" From b4a0e656abbf19a6cdd9f5a8e57d6851de730b0a Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Sun, 3 May 2015 20:03:48 +0200 Subject: [PATCH 649/665] trac #18355: Fix broken (internet) doctests --- src/sage/finance/stock.py | 67 +++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index 321fcc0d849..a77297e5e1b 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -278,20 +278,19 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% sage: finance.Stock('vmw').history('Aug+13,+2007')[:5] # optional -- internet [ - 14-Aug-07 51.99 55.50 48.00 51.00 38253700, - 15-Aug-07 52.11 59.87 51.50 57.71 10487000, - 16-Aug-07 60.99 61.49 52.71 56.99 6641500, - 17-Aug-07 59.00 59.00 54.45 55.55 2983800, - 20-Aug-07 56.05 57.50 55.61 57.33 2077200 + 14-Aug-07 50.00 55.50 48.00 51.00 38262850, + 15-Aug-07 52.11 59.87 51.50 57.71 10689100, + 16-Aug-07 60.99 61.49 52.71 56.99 6919500, + 17-Aug-07 59.00 59.00 54.45 55.55 3087000, + 20-Aug-07 56.05 57.50 55.61 57.33 2141900 ] - - sage: finance.Stock('F').history('Jan+3,+1978', 'Jul+7,+2008')[:5] # optional -- internet + sage: finance.Stock('F').history('Aug+20,+1992', 'Jul+7,+2008')[:5] # optional -- internet [ - 3-Jan-78 0.00 1.93 1.89 1.89 1618200, - 4-Jan-78 0.00 1.89 1.87 1.88 2482700, - 5-Jan-78 0.00 1.89 1.84 1.84 2994900, - 6-Jan-78 0.00 1.84 1.82 1.83 3042500, - 9-Jan-78 0.00 1.81 1.79 1.81 3916400 + 20-Aug-92 0.00 7.90 7.73 7.83 5492698, + 21-Aug-92 0.00 7.92 7.66 7.68 5345999, + 24-Aug-92 0.00 7.59 7.33 7.35 11056299, + 25-Aug-92 0.00 7.66 7.38 7.61 8875299, + 26-Aug-92 0.00 7.73 7.64 7.68 6447201 ] Note that when ``startdate`` is too far prior to a stock's actual start @@ -301,11 +300,11 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% sage: finance.Stock('AAPL').history('Sep+1,+1900', 'Jan+1,+2000')[0:5] # optional -- internet [ - 4-Jan-99 0.00 2.64 2.50 2.58 136126400, - 5-Jan-99 0.00 2.75 2.59 2.71 201441600, - 6-Jan-99 0.00 2.76 2.56 2.61 192643200, - 7-Jan-99 0.00 2.82 2.63 2.81 204145600, - 8-Jan-99 0.00 2.93 2.75 2.81 96960000 + 4-Jan-99 0.00 1.51 1.43 1.47 238221200, + 5-Jan-99 0.00 1.57 1.48 1.55 352522800, + 6-Jan-99 0.00 1.58 1.46 1.49 337125600, + 7-Jan-99 0.00 1.61 1.50 1.61 357254800, + 8-Jan-99 0.00 1.67 1.57 1.61 169680000 ] Here is an example where we create and get the history of a stock @@ -329,11 +328,11 @@ def history(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+% sage: sage.finance.stock.Stock("AAPL", 22144).history(startdate='Jan+1,+1990')[:5] #optional -- internet [ - 2-Jan-90 0.00 9.38 8.75 9.31 6542800, - 3-Jan-90 0.00 9.50 9.38 9.38 7428400, - 4-Jan-90 0.00 9.69 9.31 9.41 7911200, - 5-Jan-90 0.00 9.56 9.25 9.44 4404000, - 8-Jan-90 0.00 9.50 9.25 9.50 3627600 + 8-Jun-99 0.00 1.74 1.70 1.70 78414000, + 9-Jun-99 0.00 1.73 1.69 1.73 88446400, + 10-Jun-99 0.00 1.72 1.69 1.72 79262400, + 11-Jun-99 0.00 1.73 1.65 1.66 46261600, + 14-Jun-99 0.00 1.67 1.61 1.62 39270000 ] """ @@ -387,11 +386,11 @@ def open(self, *args, **kwds): sage: c = finance.Stock('vmw') # optional -- internet sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet [ - 1-Feb-08 56.98 58.14 55.06 57.85 2473000, - 4-Feb-08 58.00 60.47 56.91 58.05 1816500, - 5-Feb-08 57.60 59.30 57.17 59.30 1709000, - 6-Feb-08 60.32 62.00 59.50 61.52 2191100, - 7-Feb-08 60.50 62.75 59.56 60.80 1511900 + 1-Feb-08 56.98 58.14 55.06 57.85 2490481, + 4-Feb-08 58.00 60.47 56.91 58.05 1840709, + 5-Feb-08 57.60 59.30 57.17 59.30 1712179, + 6-Feb-08 60.32 62.00 59.50 61.52 2211775, + 7-Feb-08 60.50 62.75 59.56 60.80 1521651 ] sage: c.open() # optional -- internet [56.9800, 58.0000, 57.6000, 60.3200, ... 56.5500, 59.3000, 60.0000, 59.7900, 59.2600] @@ -446,11 +445,11 @@ def close(self, *args, **kwds): sage: c = finance.Stock('vmw') # optional -- internet sage: c.history(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5] # optional -- internet [ - 1-Feb-08 56.98 58.14 55.06 57.85 2473000, - 4-Feb-08 58.00 60.47 56.91 58.05 1816500, - 5-Feb-08 57.60 59.30 57.17 59.30 1709000, - 6-Feb-08 60.32 62.00 59.50 61.52 2191100, - 7-Feb-08 60.50 62.75 59.56 60.80 1511900 + 1-Feb-08 56.98 58.14 55.06 57.85 2490481, + 4-Feb-08 58.00 60.47 56.91 58.05 1840709, + 5-Feb-08 57.60 59.30 57.17 59.30 1712179, + 6-Feb-08 60.32 62.00 59.50 61.52 2211775, + 7-Feb-08 60.50 62.75 59.56 60.80 1521651 ] sage: c.close() # optional -- internet [57.8500, 58.0500, 59.3000, 61.5200, ... 58.2900, 60.1800, 59.8600, 59.9500, 58.6700] @@ -579,8 +578,8 @@ def _get_data(self, exchange='', startdate='Jan+1,+1900', enddate=date.today().s sage: finance.Stock('aapl').history(startdate='Jan+1,+1990',enddate='Jan+1,+1991')[:2] # optional -- internet [ - 2-Jan-90 0.00 2.34 2.19 2.33 26171200, - 3-Jan-90 0.00 2.38 2.34 2.34 29713600 + 2-Jan-90 0.00 1.34 1.25 1.33 45799600, + 3-Jan-90 0.00 1.36 1.34 1.34 51998800 ] TESTS:: From 8686e1ac5462f69bf7ca392e3de5fc3a7c66a562 Mon Sep 17 00:00:00 2001 From: Andrey Novoseltsev Date: Sun, 3 May 2015 12:29:07 -0600 Subject: [PATCH 650/665] Fix doctests and drop \color tweaks - MathJax 2.5 does not need them. --- .../numerical/interactive_simplex_method.py | 112 ++++++++---------- 1 file changed, 52 insertions(+), 60 deletions(-) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 4a7db2b3524..0c51ecaee8a 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -53,9 +53,9 @@ \begin{array}{l} \begin{array}{lcrcrcl} - \max \!\!\!&\!\!\! \!\!\!&\!\!\! 10 C \!\!\!&\!\!\! + \!\!\!&\!\!\! 5 B \!\!\! \\ - \!\!\!&\!\!\! \!\!\!&\!\!\! C \!\!\!&\!\!\! + \!\!\!&\!\!\! B \!\!\!&\!\!\! \leq \!\!\!&\!\!\! 1000 \\ - \!\!\!&\!\!\! \!\!\!&\!\!\! 3 C \!\!\!&\!\!\! + \!\!\!&\!\!\! B \!\!\!&\!\!\! \leq \!\!\!&\!\!\! 1500 \\ + \max \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 10 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 B \mspace{-6mu} \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1000 \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 3 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1500 \\ \end{array} \\ C, B \geq 0 \end{array} @@ -83,7 +83,8 @@ The simplest way to use the simplex method is:: sage: P.run_simplex_method() - '...' + %notruncate + ... (This method produces quite long formulas which have been omitted here.) But, of course, it is much more fun to do most of the steps by hand. Let's start @@ -100,10 +101,10 @@ \renewcommand{\arraystretch}{1.5} \begin{array}{|rcrcrcr|} \hline - x_{3} \!\!\!&\!\!\! = \!\!\!&\!\!\! 1000 \!\!\!&\!\!\! - \!\!\!&\!\!\! C \!\!\!&\!\!\! - \!\!\!&\!\!\! B\\ - x_{4} \!\!\!&\!\!\! = \!\!\!&\!\!\! 1500 \!\!\!&\!\!\! - \!\!\!&\!\!\! 3 C \!\!\!&\!\!\! - \!\!\!&\!\!\! B\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} C \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} B\\ + x_{4} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1500 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} 3 C \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} B\\ \hline - z \!\!\!&\!\!\! = \!\!\!&\!\!\! 0 \!\!\!&\!\!\! + \!\!\!&\!\!\! 10 C \!\!\!&\!\!\! + \!\!\!&\!\!\! 5 B\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 0 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 10 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 B\\ \hline \end{array} @@ -228,11 +229,13 @@ def _assemble_arrayl(lines, stretch=None): ....: import _assemble_arrayl sage: lines = ["1 + 1", "2"] sage: print _assemble_arrayl(lines) + %notruncate \begin{array}{l} 1 + 1\\ 2 \end{array} sage: print _assemble_arrayl(lines, 1.5) + %notruncate \renewcommand{\arraystretch}{1.500000} \begin{array}{l} 1 + 1\\ @@ -294,7 +297,7 @@ def _latex_product(coefficients, variables, sage: var("x, y") (x, y) sage: print _latex_product([-1, 3], [x, y]) - - & x & + & 3 y + - \mspace{-6mu}&\mspace{-6mu} x \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 3 y """ entries = [] for c, v in zip(coefficients, variables): @@ -463,9 +466,9 @@ class InteractiveLPProblem(SageObject): \begin{array}{l} \begin{array}{lcrcrcl} - \max \!\!\!&\!\!\! \!\!\!&\!\!\! 10 C \!\!\!&\!\!\! + \!\!\!&\!\!\! 5 B \!\!\! \\ - \!\!\!&\!\!\! \!\!\!&\!\!\! C \!\!\!&\!\!\! + \!\!\!&\!\!\! B \!\!\!&\!\!\! \leq \!\!\!&\!\!\! 1000 \\ - \!\!\!&\!\!\! \!\!\!&\!\!\! 3 C \!\!\!&\!\!\! + \!\!\!&\!\!\! B \!\!\!&\!\!\! \leq \!\!\!&\!\!\! 1500 \\ + \max \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 10 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 B \mspace{-6mu} \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1000 \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 3 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1500 \\ \end{array} \\ C, B \geq 0 \end{array} @@ -615,11 +618,11 @@ def _latex_(self): sage: c = (10, 5) sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: print P._latex_() - \begin{array}{l} \setlength{\arraycolsep}{0.125em} + \begin{array}{l} \begin{array}{lcrcrcl} - \max & & 10 C & + & 5 B\\ - & & C & + & B & \leq & 1000 \\ - & & 3 C & + & B & \leq & 1500 \\ + \max \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 10 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 B \mspace{-6mu} \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1000 \\ + \mspace{-6mu}&\mspace{-6mu} \mspace{-6mu}&\mspace{-6mu} 3 C \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} B \mspace{-6mu}&\mspace{-6mu} \leq \mspace{-6mu}&\mspace{-6mu} 1500 \\ \end{array} \\ C, B \geq 0 \end{array} @@ -1846,6 +1849,7 @@ def run_revised_simplex_method(self): sage: c = (10, 5) sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: P.run_revised_simplex_method() + %notruncate \renewcommand{\arraystretch}{1.500000} \begin{array}{l} ... @@ -1928,22 +1932,22 @@ def run_simplex_method(self): `\LaTeX` code:: sage: print P.run_simplex_method() - \begin{gather*} + %notruncate ... - \text{The initial dictionary is infeasible, solving auxiliary problem.}\displaybreak[0]\\ + \text{The initial dictionary is infeasible, solving auxiliary problem.}\\ ... - \text{Entering: $x_{0}$. Leaving: $x_{5}$.}\displaybreak[0]\\ + \text{Entering: $x_{0}$. Leaving: $x_{5}$.}\\ ... - \text{Entering: $x_{1}$. Leaving: $x_{0}$.}\displaybreak[0]\\ + \text{Entering: $x_{1}$. Leaving: $x_{0}$.}\\ ... - \text{Back to the original problem.}\displaybreak[0]\\ + \text{Back to the original problem.}\\ ... - \text{Entering: $x_{5}$. Leaving: $x_{4}$.}\displaybreak[0]\\ + \text{Entering: $x_{5}$. Leaving: $x_{4}$.}\\ ... - \text{Entering: $x_{2}$. Leaving: $x_{3}$.}\displaybreak[0]\\ + \text{Entering: $x_{2}$. Leaving: $x_{3}$.}\\ ... \text{The optimal value: $6250$. An optimal solution: $\left(250,\,750\right)$.} - \end{gather*} + ... """ result = [] d = self.initial_dictionary() @@ -2716,13 +2720,13 @@ def _latex_(self): sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: print D._latex_() - \renewcommand{\arraystretch}{1.5} \setlength{\arraycolsep}{0.125em} + \renewcommand{\arraystretch}{1.5} \begin{array}{|rcrcrcr|} \hline - x_{3} & = & 1000 & - & x_{1} & - & x_{2}\\ - x_{4} & = & 1500 & - & 3 x_{1} & - & x_{2}\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} x_{1} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} x_{2}\\ + x_{4} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1500 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} 3 x_{1} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} x_{2}\\ \hline - z & = & 0 & + & 10 x_{1} & + & 5 x_{2}\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 0 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 10 x_{1} \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 x_{2}\\ \hline \end{array} """ @@ -2750,8 +2754,6 @@ def _latex_(self): for i, line in enumerate(lines): line = line.split("&") if len(line) > 1: - if not generate_real_LaTeX: - line[e] = ("{" + line[e] + "}").replace(r"\\}", r"}\\") line[e] = r"\color{green}" + line[e] lines[i] = "&".join(line) if self._leaving is not None: @@ -2759,16 +2761,9 @@ def _latex_(self): l = tuple(B).index(self._leaving) + 3 line = lines[l].split("&") for i, term in enumerate(line): - if not generate_real_LaTeX: - term = ("{" + term + "}").replace(r"\\}", r"}\\") line[i] = r"\color{red}" + term line = "&".join(line) - if generate_real_LaTeX: - line = line.replace(r"\color{red}\color{green}", - r"\color{blue}") - else: - line = line.replace(r"\color{red}{\color{green}", - r"\color{blue}{") + line = line.replace(r"\color{red}\color{green}", r"\color{blue}") lines[l] = line return "\n".join(lines) @@ -2794,20 +2789,20 @@ def ELLUL(self, entering, leaving): sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() sage: D.ELLUL("x1", "x4") - \renewcommand{\arraystretch}{1.5} \setlength{\arraycolsep}{0.125em} + \renewcommand{\arraystretch}{1.5} \begin{array}{|rcrcrcr|} \hline - x_{3} & = & 1000 & - &\color{green} x_{1} & - & x_{2}\\ - \color{red}x_{4} &\color{red} = &\color{red} 1500 &\color{red} - &\color{blue} 3 x_{1} &\color{red} - &\color{red} x_{2}\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\color{green}\mspace{-6mu} x_{1} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} x_{2}\\ + \color{red}x_{4} \mspace{-6mu}&\color{red}\mspace{-6mu} = \mspace{-6mu}&\color{red}\mspace{-6mu} 1500 \mspace{-6mu}&\color{red}\mspace{-6mu} - \mspace{-6mu}&\color{blue}\mspace{-6mu} 3 x_{1} \mspace{-6mu}&\color{red}\mspace{-6mu} - \mspace{-6mu}&\color{red}\mspace{-6mu} x_{2}\\ \hline - z & = & 0 & + &\color{green} 10 x_{1} & + & 5 x_{2}\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 0 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\color{green}\mspace{-6mu} 10 x_{1} \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 x_{2}\\ \hline - \multicolumn{2}{c}{}\\[-3ex] + \\ \hline - x_{3} & = & 500 & + & \frac{1}{3} x_{4} & - & \frac{2}{3} x_{2}\\ - x_{1} & = & 500 & - & \frac{1}{3} x_{4} & - & \frac{1}{3} x_{2}\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 500 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{2}{3} x_{2}\\ + x_{1} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 500 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{2}\\ \hline - z & = & 5000 & - & \frac{10}{3} x_{4} & + & \frac{5}{3} x_{2}\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 5000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{10}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} \frac{5}{3} x_{2}\\ \hline \end{array} @@ -2818,17 +2813,17 @@ def ELLUL(self, entering, leaving): \renewcommand{\arraystretch}{1.5} \begin{array}{|rcrcrcr|} \hline - x_{3} \!\!\!&\!\!\! = \!\!\!&\!\!\! 1000 \!\!\!&\!\!\! - \!\!\!&\color{green}{\!\!\! x_{1} \!\!\!}&\!\!\! - \!\!\!&\!\!\! x_{2}\\ - \color{red}{x_{4} \!\!\!}&\color{red}{\!\!\! = \!\!\!}&\color{red}{\!\!\! 1500 \!\!\!}&\color{red}{\!\!\! - \!\!\!}&\color{blue}{{\!\!\! 3 x_{1} \!\!\!}}&\color{red}{\!\!\! - \!\!\!}&\color{red}{\!\!\! x_{2}}\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 1000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\color{green}\mspace{-6mu} x_{1} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} x_{2}\\ + \color{red}x_{4} \mspace{-6mu}&\color{red}\mspace{-6mu} = \mspace{-6mu}&\color{red}\mspace{-6mu} 1500 \mspace{-6mu}&\color{red}\mspace{-6mu} - \mspace{-6mu}&\color{blue}\mspace{-6mu} 3 x_{1} \mspace{-6mu}&\color{red}\mspace{-6mu} - \mspace{-6mu}&\color{red}\mspace{-6mu} x_{2}\\ \hline - z \!\!\!&\!\!\! = \!\!\!&\!\!\! 0 \!\!\!&\!\!\! + \!\!\!&\color{green}{\!\!\! 10 x_{1} \!\!\!}&\!\!\! + \!\!\!&\!\!\! 5 x_{2}\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 0 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\color{green}\mspace{-6mu} 10 x_{1} \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} 5 x_{2}\\ \hline \\ \hline - x_{3} \!\!\!&\!\!\! = \!\!\!&\!\!\! 500 \!\!\!&\!\!\! + \!\!\!&\!\!\! \frac{1}{3} x_{4} \!\!\!&\!\!\! - \!\!\!&\!\!\! \frac{2}{3} x_{2}\\ - x_{1} \!\!\!&\!\!\! = \!\!\!&\!\!\! 500 \!\!\!&\!\!\! - \!\!\!&\!\!\! \frac{1}{3} x_{4} \!\!\!&\!\!\! - \!\!\!&\!\!\! \frac{1}{3} x_{2}\\ + x_{3} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 500 \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{2}{3} x_{2}\\ + x_{1} \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 500 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{1}{3} x_{2}\\ \hline - z \!\!\!&\!\!\! = \!\!\!&\!\!\! 5000 \!\!\!&\!\!\! - \!\!\!&\!\!\! \frac{10}{3} x_{4} \!\!\!&\!\!\! + \!\!\!&\!\!\! \frac{5}{3} x_{2}\\ + z \mspace{-6mu}&\mspace{-6mu} = \mspace{-6mu}&\mspace{-6mu} 5000 \mspace{-6mu}&\mspace{-6mu} - \mspace{-6mu}&\mspace{-6mu} \frac{10}{3} x_{4} \mspace{-6mu}&\mspace{-6mu} + \mspace{-6mu}&\mspace{-6mu} \frac{5}{3} x_{2}\\ \hline \end{array} @@ -3192,7 +3187,7 @@ class LPRevisedDictionary(LPAbstractDictionary): \renewcommand{\arraystretch}{1.500000} \begin{array}{l} \begin{array}{l|r|rr||r||r} - x_B & c_B & & \!\!\!\!\!\!\!\! B^{-1} & y & B^{-1} b \\ + x_B & c_B & & \mspace{-16mu} B^{-1} & y & B^{-1} b \\ \hline x_{1} & 10 & -\frac{1}{2} & \frac{1}{2} & \frac{5}{2} & 250 \\ x_{2} & 5 & \frac{3}{2} & -\frac{1}{2} & \frac{5}{2} & 750 \\ @@ -3202,6 +3197,7 @@ class LPRevisedDictionary(LPAbstractDictionary): x_N & x_{3} & x_{4} \\ \hline c_N^T & 0 & 0 \\ + \hline y^T A_N & \frac{5}{2} & \frac{5}{2} \\ \hline c_N^T - y^T A_N & -\frac{5}{2} & -\frac{5}{2} \\ @@ -3291,10 +3287,11 @@ def _latex_(self): sage: D.enter(1) sage: D.leave(3) sage: print D._latex_() + %notruncate \renewcommand{\arraystretch}{1.500000} \begin{array}{l} \begin{array}{l|r|rr||r||r|r|r} - x_B & c_B & \multicolumn{2}{c||}{B^{-1}} & y & B^{-1} b & B^{-1} A_{x_{1}} & \hbox{Ratio} \\ + x_B & c_B & & \mspace{-16mu} B^{-1} & y & B^{-1} b & B^{-1} A_{x_{1}} & \hbox{Ratio} \\ \hline \color{red} x_{3} & \color{red} 0 & \color{red} 1 & \color{red} 0 & 0 & \color{red} 1000 & \color{red} 1 & \color{red} 1000 \\ x_{4} & 0 & 0 & 1 & 0 & 1500 & 3 & 500 \\ @@ -3327,7 +3324,7 @@ def _latex_(self): headers.append(r"\multicolumn{%d}{c||}{B^{-1}}" % m) else: headers.extend([""] * (m//2)) - headers.append(r"\!\!\!\!\!\!\!\! B^{-1}") + headers.append(r"\mspace{-16mu} B^{-1}") headers.extend([""] * ((m-1)//2)) headers.extend(["y", "B^{-1} b"]) if entering is not None: @@ -3358,8 +3355,6 @@ def _latex_(self): for j, t in enumerate(terms): if j == m + 2: continue - if not generate_real_LaTeX: - t = "{" + t + "}" terms[j] = r"\color{red} " + t lines.append(" & ".join(terms) + r" \\") lines.append(r"\end{array}") @@ -3368,10 +3363,7 @@ def _latex_(self): def make_line(header, terms): terms = map(latex, terms) if entering is not None: - t = terms[k] - if not generate_real_LaTeX: - t = "{" + t + "}" - terms[k] = r"\color{green} " + t + terms[k] = r"\color{green} " + terms[k] lines.append(" & ".join([header] + terms) + r" \\") lines = [] From e685dcd2dcf7bd8d74efda055ecca94d38df7ae9 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 4 May 2015 07:33:00 +0200 Subject: [PATCH 651/665] trac #18355: Broken doctest --- src/sage/finance/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/finance/stock.py b/src/sage/finance/stock.py index a77297e5e1b..cfbf8f72a71 100644 --- a/src/sage/finance/stock.py +++ b/src/sage/finance/stock.py @@ -167,7 +167,7 @@ def current_price_data(self): EXAMPLES:: - sage: finance.Stock('GOOG').current_price_data() # random + sage: finance.Stock('GOOG').current_price_data() # random; optional - internet {'200day_moving_avg': '536.57', '50day_moving_avg': '546.01', '52_week_high': '599.65', From 6ffbb05999f70fa2535f28aca08b203036664491 Mon Sep 17 00:00:00 2001 From: Nathann Cohen Date: Mon, 4 May 2015 07:43:05 +0200 Subject: [PATCH 652/665] trac #18346; Broken doctest --- src/sage/graphs/base/overview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/base/overview.py b/src/sage/graphs/base/overview.py index 40028a9b62d..787f37fa065 100644 --- a/src/sage/graphs/base/overview.py +++ b/src/sage/graphs/base/overview.py @@ -48,7 +48,7 @@ `:: sage: Graph()._backend - + A (di)graph backend is a simpler (di)graph class having only the most elementary methods (e.g.: add/remove vertices/edges). Its vertices can be arbitrary From 5249809481c4366e0ea5f9efc0f89b27ce7bc7fd Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 4 May 2015 08:44:11 +0200 Subject: [PATCH 653/665] Remove mention of get_fltk.patch --- build/pkgs/pari/patches/README.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/pkgs/pari/patches/README.txt b/build/pkgs/pari/patches/README.txt index cd367f24312..93ac577bd55 100644 --- a/build/pkgs/pari/patches/README.txt +++ b/build/pkgs/pari/patches/README.txt @@ -7,8 +7,6 @@ Patches to configuration files: * get_config_options.patch (Leif Leonhardy): Catch invalid arguments to "--graphic" (and treat such as an error) since otherwise strange compilation errors might occur (cf. #9722, too). -* get_fltk.patch (Leif Leonhardy): do an extra check for the FLTK - include dir (cf. #9722). * get_dlcflags.patch (Jeroen Demeyer): Add -fno-common to DLCFLAGS on Darwin. Submitted upstream, but upstream only applied it for PowerPC. Since this doesn't break anything and only improves performance, add From 4ade279cb4e0bf5965f907ff498168967cd23add Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Mon, 4 May 2015 11:47:59 +0200 Subject: [PATCH 654/665] Use PyNumber_Index --- .../rings/polynomial/polynomial_integer_dense_flint.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 7135ef9eb61..e5b2f075df8 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -55,7 +55,7 @@ from sage.libs.flint.fmpz_poly cimport fmpz_poly_reverse, fmpz_poly_revert_serie from sage.libs.flint.ntl_interface cimport fmpz_set_ZZ, fmpz_poly_set_ZZX, fmpz_poly_get_ZZX from sage.libs.ntl.ntl_ZZX_decl cimport * -from cpython.number cimport PyNumber_AsSsize_t +from cpython.number cimport PyNumber_Index cdef extern from "limits.h": long LONG_MAX @@ -893,18 +893,18 @@ cdef class Polynomial_integer_dense_flint(Polynomial): ZeroDivisionError: negative exponent in power of zero Check that :trac:`18278` is fixed:: - + sage: R. = ZZ[] sage: x^(1/2) Traceback (most recent call last): ... TypeError: non-integral exponents not supported """ - cdef Py_ssize_t nn + cdef long nn cdef Polynomial_integer_dense_flint res = self._new() try: - nn = PyNumber_AsSsize_t (exp, OverflowError) + nn = PyNumber_Index(exp) except TypeError: raise TypeError("non-integral exponents not supported") From 02f6ee1532e11b2acc0113e55563f1ce65067ad7 Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Mon, 4 May 2015 12:04:52 +0200 Subject: [PATCH 655/665] Remove try ... except --- .../rings/polynomial/polynomial_integer_dense_flint.pyx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index e5b2f075df8..7e7b6a7e5b7 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -900,13 +900,8 @@ cdef class Polynomial_integer_dense_flint(Polynomial): ... TypeError: non-integral exponents not supported """ - cdef long nn cdef Polynomial_integer_dense_flint res = self._new() - - try: - nn = PyNumber_Index(exp) - except TypeError: - raise TypeError("non-integral exponents not supported") + cdef long nn = PyNumber_Index(exp) if self.is_zero(): if exp == 0: @@ -924,7 +919,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): else: if self is self._parent.gen(): sig_on() - fmpz_poly_set_coeff_ui(res.__poly, exp, 1) + fmpz_poly_set_coeff_ui(res.__poly, nn, 1) sig_off() else: sig_on() From 451c49de98a9f7b1159503d777675c26917666a2 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 4 May 2015 12:06:24 +0200 Subject: [PATCH 656/665] Trac 18068: add comment about bug fixed by this ticket --- src/sage/modular/modform/element.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 0cfba997f48..0a5a8057ed9 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -222,6 +222,11 @@ def __ne__(self, other): True sage: f != f False + + TESTS:: + + The following used to fail (see :trac:`18068`):: + sage: f != loads(dumps(f)) False """ From 7b5e70299949ab09cb8bca3397ffedbc3b7e6d93 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 4 May 2015 12:53:04 +0200 Subject: [PATCH 657/665] Trac 18068: fix typo --- src/sage/modular/modform/element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 0a5a8057ed9..9c4a54cff93 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -223,7 +223,7 @@ def __ne__(self, other): sage: f != f False - TESTS:: + TESTS: The following used to fail (see :trac:`18068`):: From 10067b5735103012c8fcd0eba6e84d6cefa69573 Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 4 May 2015 13:09:38 +0200 Subject: [PATCH 658/665] Trac 18334: fixed frac + doctests --- src/sage/rings/real_mpfi.pyx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 3a559102c58..8d64b69ac4e 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -2968,6 +2968,8 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): sage: parent(_) Real Interval Field with 53 bits of precision + sage: RIF(-0.9, 0.9).trunc() + 0 sage: RIF(-7.5, -7.3).trunc() -7 @@ -3010,8 +3012,24 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): sage: r = RIF(18.222, 18.223) sage: r in (r.frac() + r.trunc()) True + + sage: RIF(1.25, 2.05).frac().endpoints() + (0.000000000000000, 1.00000000000000) + sage: RIF(-2.1,-0.9).frac().endpoints() + (-1.00000000000000, -0.000000000000000) + sage: RIF(-0.5,0.5).frac().endpoints() + (-0.500000000000000, 0.500000000000000) """ - return self.parent()(self.lower().frac(), self.upper().frac()) + a = self.lower() + b = self.upper() + P = self.parent() + r = P(a.frac(), b.frac()) + if b.floor() > max(a,0): + # result contains [0,1] + r = r.union(P(0, 1)) + if a.ceil() < min(b,0): + r = r.union(P(-1, 0)) + return r ########################################### # Conversions @@ -3265,9 +3283,9 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): if a == b: return a elif a < b: - raise ValueError, "interval contains more than one integer" + raise ValueError("interval contains more than one integer") else: - raise ValueError, "interval contains no integer" + raise ValueError("interval contains no integer") def simplest_rational(self, low_open=False, high_open=False): """ From 7d0bc5c99228b11b9cf1d3d180edaeed2d34343e Mon Sep 17 00:00:00 2001 From: Bruno Grenet Date: Mon, 4 May 2015 13:42:35 +0200 Subject: [PATCH 659/665] Doctests --- .../rings/polynomial/polynomial_integer_dense_flint.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 7e7b6a7e5b7..0ab0143b3b3 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -898,7 +898,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: x^(1/2) Traceback (most recent call last): ... - TypeError: non-integral exponents not supported + TypeError: rational is not an integer + sage: x^(2^100) + Traceback (most recent call last): + ... + OverflowError: Python int too large to convert to C long """ cdef Polynomial_integer_dense_flint res = self._new() cdef long nn = PyNumber_Index(exp) From 7fe18d6e2d9b459340c9c6e1527a6eb4ebd4e24e Mon Sep 17 00:00:00 2001 From: Vincent Delecroix <20100.delecroix@gmail.com> Date: Mon, 4 May 2015 14:48:50 +0200 Subject: [PATCH 660/665] Trac 18334: more doctests --- src/sage/rings/real_mpfi.pyx | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 8d64b69ac4e..a7049662681 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -2993,6 +2993,14 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): an integer. The integer `x-y` can be obtained through the method :meth:`trunc`. + The output of this function is the smallest interval that contains all + possible values of `frac(x)` for `x` in this interval. Note that if it + contains an integer then the answer might not be very meaningful. More + precisely, if the endpoints are `a` and `b` then: + + - if `floor(b) > \max(a,0)` then the interval obtained contains `[0,1]`, + - if `ceil(a) < \min(b,0)` then the interval obtained contains `[-1,0]`. + .. SEEALSO:: :meth:`trunc` -- return the integer part complement to this @@ -3005,6 +3013,11 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): sage: RIF(-23.12, -23.13).frac() -0.13? + sage: RIF(.5, 1).frac().endpoints() + (0.000000000000000, 1.00000000000000) + sage: RIF(1, 1.5).frac().endpoints() + (0.000000000000000, 0.500000000000000) + sage: r = RIF(-22.47, -22.468) sage: r in (r.frac() + r.trunc()) True @@ -3013,8 +3026,13 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): sage: r in (r.frac() + r.trunc()) True - sage: RIF(1.25, 2.05).frac().endpoints() + sage: RIF(1.99, 2.025).frac().endpoints() + (0.000000000000000, 1.00000000000000) + sage: RIF(1.99, 2.00).frac().endpoints() (0.000000000000000, 1.00000000000000) + sage: RIF(2.00, 2.025).frac().endpoints() + (0.000000000000000, 0.0250000000000000) + sage: RIF(-2.1,-0.9).frac().endpoints() (-1.00000000000000, -0.000000000000000) sage: RIF(-0.5,0.5).frac().endpoints() @@ -3025,7 +3043,6 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): P = self.parent() r = P(a.frac(), b.frac()) if b.floor() > max(a,0): - # result contains [0,1] r = r.union(P(0, 1)) if a.ceil() < min(b,0): r = r.union(P(-1, 0)) From 6a3cb27234c22f76062ebc9c7d4ecff6fbb1578a Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Tue, 5 May 2015 11:50:48 +0200 Subject: [PATCH 661/665] Updated Sage version to 6.7.beta4 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 2 +- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index f0da0df6c91..a3f20aceb00 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -Sage version 6.7.beta3, released 2015-04-28 +Sage version 6.7.beta4, released 2015-05-05 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 988f1ba2eec..89b431e6de7 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=d0a00ec9d7e49ef6e758aee29f60cd399b2a8ff9 -md5=cbf68f077445ecb657e52276762d7e44 -cksum=3915828491 +sha1=17ccf81f7596c2bc80a90e679af69e1e51cf8ae0 +md5=7e005e5e569fa0a2c10f664a9ca19cc9 +cksum=4206119317 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 8643cf6deba..d61f00d8cad 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -89 +90 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index e3d6f783189..3e8d31f0952 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath Version 6.7.beta3, Release Date: 2015-04-28 │ +│ SageMath Version 6.7.beta4, Release Date: 2015-05-05 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index c352e438a0c..176de20d617 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='6.7.beta3' -SAGE_RELEASE_DATE='2015-04-28' +SAGE_VERSION='6.7.beta4' +SAGE_RELEASE_DATE='2015-05-05' diff --git a/src/sage/version.py b/src/sage/version.py index a4170d89280..4f26839dc10 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '6.7.beta3' -date = '2015-04-28' +version = '6.7.beta4' +date = '2015-05-05' From 4f3489b15538f1a8a7d64e27e207d262ceb99038 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Thu, 7 May 2015 06:31:14 +0200 Subject: [PATCH 662/665] Trac #17218: Replace cdef _richcmp_c_impl by cpdef _richcmp_ (cf. #17890) --- src/sage/rings/complex_ball_acb.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 35ba7a56f72..b8a37129fec 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -605,7 +605,7 @@ cdef class ComplexBall(Element): """ return (left)._richcmp(right, op) - cdef _richcmp_c_impl(left, Element right, int op): + cpdef _richcmp_(left, Element right, int op): """ Compare ``left`` and ``right``. From d671d8301670759f2e84b2155d0311b746d2aec9 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 18 May 2015 18:53:13 +0200 Subject: [PATCH 663/665] Trac #17218: Call Element.__init__ directly Instead of calling super(ComplexBall, self).__init__(parent), call Element.__init__(self, parent), see http://trac.sagemath.org/ticket/17218#comment:14 . --- src/sage/rings/complex_ball_acb.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index b8a37129fec..31821bd44d6 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -393,7 +393,7 @@ cdef class ComplexBall(Element): sage: ComplexBallField(106)(1/3, 1/6) # optional - arb [0.33333333333333333333333333333333 +/- 6.94e-33] + [0.16666666666666666666666666666666 +/- 7.70e-33]*I """ - super(ComplexBall, self).__init__(parent) + Element.__init__(self, parent) if x is None: return From b559917b076f8c55fc90e1df6429bcc561363a66 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 18 May 2015 19:11:44 +0200 Subject: [PATCH 664/665] Trac #17218: rewrite comparison No comparison is needed to check if two complex balls are different. http://trac.sagemath.org/ticket/17218#comment:14 --- src/sage/libs/arb/acb.pxd | 1 + src/sage/rings/complex_ball_acb.pyx | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/libs/arb/acb.pxd b/src/sage/libs/arb/acb.pxd index 595e73e6194..61336196ee3 100644 --- a/src/sage/libs/arb/acb.pxd +++ b/src/sage/libs/arb/acb.pxd @@ -16,6 +16,7 @@ cdef extern from "acb.h": void acb_set_ui(acb_t z, unsigned long c) bint acb_equal(const acb_t x, const acb_t y) + bint acb_overlaps(const acb_t x, const acb_t y) void acb_add(acb_t z, const acb_t x, const acb_t y, long prec) void acb_sub(acb_t z, const acb_t x, const acb_t y, long prec) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index 31821bd44d6..ebcb8f73314 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -701,11 +701,7 @@ cdef class ComplexBall(Element): and acb_equal(lt.value, rt.value)) if op == Py_NE: - acb_init(difference) - acb_sub(difference, lt.value, rt.value, prec(lt)) - result = acb_is_nonzero(difference) - acb_clear(difference) + return not acb_overlaps(lt.value, rt.value) + elif op == Py_GT or op == Py_GE or op == Py_LT or op == Py_LE: raise TypeError("No order is defined for ComplexBalls.") - - return result From b666ea200def5384fa56ae9266ceeed5586fc86d Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 18 May 2015 19:20:14 +0200 Subject: [PATCH 665/665] Trac #17218: mark as experimental --- src/sage/rings/complex_ball_acb.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/complex_ball_acb.pyx b/src/sage/rings/complex_ball_acb.pyx index ebcb8f73314..6823960c101 100644 --- a/src/sage/rings/complex_ball_acb.pyx +++ b/src/sage/rings/complex_ball_acb.pyx @@ -27,6 +27,9 @@ or if both are exact and equal:: sage: from sage.rings.complex_ball_acb import ComplexBallField # optional - arb sage: CBF = ComplexBallField() # optional - arb + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/17218 for details. sage: a = CBF(1, 2) # optional - arb sage: b = CBF(1, 2) # optional - arb sage: a is b # optional - arb @@ -75,6 +78,7 @@ include "sage/ext/stdsage.pxi" import sage.categories.fields from sage.libs.arb.arb cimport * from sage.libs.arb.acb cimport * +from sage.misc.superseded import experimental from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.real_arb cimport mpfi_to_arb, arb_to_mpfi from sage.rings.real_arb import RealBallField @@ -169,6 +173,7 @@ class ComplexBallField(UniqueRepresentation, Parent): """ return super(ComplexBallField, cls).__classcall__(cls, precision) + @experimental(17218) def __init__(self, precision): r""" Initialize the complex ball field.